我有一个沿着Bezier曲线移动的物体,但是我有多个物体需要按照此路径顺序移动,但它们都同时跟随。该物体是太空射击游戏中的蛇型敌人。 >
到目前为止,我一直试图使所有对象成为子对象,但是这样做时,按照贝塞尔曲线,它们与父对象保持一条直线。 我还使所有对象分离,并将Bezier脚本附加到这些对象上,以便它们都遵循相同的路径,并且可以工作,但只有它们同时遵循相同的路径。
public class BezierFollow : MonoBehaviour{
[SerializeField]
private Transform[] routes;
private int routeToGo;
private float tParam;
private Vector2 enemyPosition;
[SerializeField]
public float speedModifier = 0.5f;
private bool coroutineAloud;
// Start is called before the first frame update
void Start()
{
routeToGo = 0;
tParam = 0f;
//speedModifier = 0.5f;
coroutineAloud = true;
}
// Update is called once per frame
void Update()
{
if (coroutineAloud)
{
StartCoroutine(GoByTheRouteRoutine(routeToGo));
}
}
private IEnumerator GoByTheRouteRoutine(int routeNumber)
{
coroutineAloud = false;
Vector2 p0 = routes[routeNumber].GetChild(0).position;
Vector2 p1 = routes[routeNumber].GetChild(1).position;
Vector2 p2 = routes[routeNumber].GetChild(2).position;
Vector2 p3 = routes[routeNumber].GetChild(3).position;
while(tParam < 1)
{
tParam += Time.deltaTime * speedModifier;
enemyPosition = Mathf.Pow(1 - tParam, 3) * p0 +
3 * Mathf.Pow(1 - tParam, 2) * tParam * p1 +
3 * (1 - tParam) * Mathf.Pow(tParam, 2) * p2 +
Mathf.Pow(tParam, 3) * p3;
transform.position = enemyPosition;
yield return new WaitForEndOfFrame();
}
tParam = 0f;
routeToGo += 1;
if(routeToGo > routes.Length - 1)
routeToGo = 0;
coroutineAloud = true;
}}
这是我认为您不需要的路线脚本,但会包含此脚本
public class Route : MonoBehaviour{
[SerializeField]
private Transform[] controlPoints;
private Vector2 gizmosPos;
private void OnDrawGizmos()
{
for(float t = 0; t <= 1; t += 0.05f)
{
gizmosPos = Mathf.Pow(1 - t, 3) * controlPoints[0].position +
3 * Mathf.Pow(1 - t, 2) * t * controlPoints[1].position +
3 * (1 - t) * Mathf.Pow(t, 2) * controlPoints[2].position +
Mathf.Pow(t, 3) * controlPoints[3].position;
Gizmos.DrawSphere(gizmosPos, 0.25f);
}
Gizmos.DrawLine(new Vector2(controlPoints[0].position.x, controlPoints[0].position.y),
new Vector2(controlPoints[1].position.x, controlPoints[1].position.y));
Gizmos.DrawLine(new Vector2(controlPoints[2].position.x, controlPoints[2].position.y),
new Vector2(controlPoints[3].position.x, controlPoints[3].position.y));
}}
我认为我需要做的是让每个对象都不是子对象,并且所有对象都附加脚本以遵循该路线,但是在沿路径执行之前还有一个延迟的时间,但是不确定如何执行此操作。我当时认为这可能需要在单独的脚本中完成,因为在贝塞尔曲线脚本中已对其进行了设置,因此一旦到达终点,对象便会在路线的起点再次开始
答案 0 :(得分:1)
我知道您要实现的目标,并且我相信您可以使用额外的脚本来完成此任务,而无需更改当前代码。
在这里,我编写了一个名为EnemyBehavior的新脚本。
public class EnemyBehavior : MonoBehaviour{
public Path pathToFollow;
//PATH INFO
public int currentWayPointID = 0;
//speeds
public float speed = 2;
public float reachDistance = 0.4f;
public float rotationSpeed = 5f;
float distance; //DISTANCE TO NEXT PATH POINT
public bool useBezier = false;
//STATE MACHINES
public enum EnemyStates
{
ON_PATH,
IDLE
}
public EnemyStates enemyState;
public int enemyID;
void Update()
{
switch (enemyState)
{
case EnemyStates.ON_PATH:
MoveOnThePath(pathToFollow);
break;
case EnemyStates.IDLE:
break;
}
}
void MoveToFormation()
{
//transform.position = Vector3.MoveTowards(transform.position, formation.gridList[enemyID], speed * Time.deltaTime);
//if(Vector3.Distance(transform.position, formation.gridList[enemyID])<= 0.001f)
{
//transform.SetParent(formation.gameObject.transform);
transform.eulerAngles = Vector3.zero;
enemyState = EnemyStates.IDLE;
}
}
void MoveOnThePath(Path path)
{
if (useBezier)
{
//MOVING THE ENEMY
distance = Vector3.Distance(path.bezierObjList[currentWayPointID], transform.position);
transform.position = Vector3.MoveTowards(transform.position, path.bezierObjList[currentWayPointID], speed * Time.deltaTime);
//ROTATION OF YOUR ENEMY
var direction = path.bezierObjList[currentWayPointID] - transform.position;
if (direction != Vector3.zero)
{
direction.z = 0;
direction = direction.normalized;
var rotation = Quaternion.LookRotation(direction);
transform.rotation = Quaternion.Slerp(transform.rotation, rotation, rotationSpeed * Time.deltaTime);
}
}
else
{
distance = Vector3.Distance(path.pathObjList[currentWayPointID].position, transform.position);
transform.position = Vector3.MoveTowards(transform.position, path.pathObjList[currentWayPointID].position, speed * Time.deltaTime);
//ROTATION OF ENEMY
var direction = path.pathObjList[currentWayPointID].position - transform.position;
if (direction != Vector3.zero)
{
direction.y = 0;
direction = direction.normalized;
var rotation = Quaternion.LookRotation(direction);
transform.rotation = Quaternion.Slerp(transform.rotation, rotation, rotationSpeed * Time.deltaTime);
}
}
}}
将此脚本附加到您打算使用该路径的所有游戏对象上,并且不要忘记在检查器中为这些对象分配路径。
如果它是2D游戏,则可能需要调整方向以适合您的需求,但这应该适合您。 让我知道您的生活状况,并随时直接与我联系。
答案 1 :(得分:0)
这种方法怎么样:
我提供了一个演示脚本代码。未经测试,但应该可以。
public class BezierCurve
{
//Starts following bezier curve.
public void StartFollow()
{
//some code here.
}
}
public class BezierCurveBatch : MonoBehaviour
{
[SerializeField]
List<BezierCurve> m_lstChildren;
[SerializeField]
float m_delayStartCurve = 10;
float m_timeLeftToStartNextChild = 0;
bool m_isRunBatchCurve = false;
/// <summary>
/// Start batch follow after each interval.
/// </summary>
public void StartBatch()
{
m_isRunBatchCurve = true;
}
private void Update()
{
if (!m_isRunBatchCurve)
return;
m_timeLeftToStartNextChild -= Time.deltaTime;
if (m_timeLeftToStartNextChild <= 0.0f)
{
if (m_lstChildren.Count > 0) //if we have children left.
{
BezierCurve l_bCurveToStart = m_lstChildren[0]; //Getting top object.
m_lstChildren.RemoveAt(0); //removing top object.
l_bCurveToStart.StartFollow(); //Start follow bezier curve
m_timeLeftToStartNextChild = m_delayStartCurve; //resetting time.
}
if (m_lstChildren.Count == 0) //After processing last object, check if need to continue for next object.
m_isRunBatchCurve = false;
}
}
}