迈向 WayPoints [C#]
Moving towards WayPoints [C#]
我遇到了这个问题:我需要敌人向目标位置移动,但我的问题是我在 Update 函数中写了这个,所以 "foreach" 语句只在一帧内完成。此外,"waypoint is reached" 语句从未显示。我该如何解决这个问题?
这是代码:`public class WayPointMovement : MonoBehaviour {
public EnemyDataSpawn enemy;
private Vector3 lastPos;
void Start ()
{
lastPos = gameObject.transform.position;
}
void Update ()
{
gameObject.transform.LookAt (LevelManager.current.playerObject.transform);
//WaypointData is a scriptable object that contains the definition of "x" and "z" coordinates.
foreach (WaypointData waypoints in enemy.enemy.waypoint) {
Debug.Log (waypoints.x);
gameObject.transform.position = Vector3.MoveTowards (gameObject.transform.position, new Vector3 (lastPos.x + waypoints.x, 0f, lastPos.z + waypoints.z), Time.deltaTime * enemy.enemy.easySpeedMovement);
if (gameObject.transform.position.x == lastPos.x + waypoints.x && gameObject.transform.position.z == lastPos.z + waypoints.z) {
Debug.Log("waypoint reached");
lastPos = gameObject.transform.position;
}
}
}
}`
您需要返工 Update
以便它只完成一帧的工作。这意味着您必须记住 a) 您要前往哪个航路点,以及 b) 您已经走了多远。只有当您真正到达下一个航路点时,您才会继续前进。
通过waypoints有两种追踪进度的方式:
1.一旦达到,您可以简单地删除 waypoints。然后,您尝试到达的航路点始终是列表中的第一个。
2。如果你想保留 waypoints,那么你需要一个额外的变量来跟踪 你当前 前往哪个 航路点。这可能类似于数组或列表的索引,或者它可能是一个枚举器 (IEnumerator<WaypointData>
),每次完成一个航路点时,您都会在其上调用 MoveNext
。
您已表明(在对此答案的评论中)您不想在到达时删除 waypoints。最灵活的安排是使用索引变量:
int waypointIndex;
void Start()
{
waypointIndex = 0;
}
void Update()
{
if (waypointIndex < waypoints.Count)
{
update position;
if (reached waypoint)
{
waypointIndex++;
}
}
}
然后,在您的 Update
方法中,您无需编写循环,而是仅更新一次游戏对象的位置,检查它是否仅到达过路点一次,如果已到达,则继续返回前的下一个航路点。如果需要多次移动才能到达一个航路点,您可以多次调用 Update
;每个Update
只是运动的一步。
您将需要更好的逻辑来确定何时到达航路点。正如其他评论者所指出的那样,对于浮点值,简单地检查它们是否 完全相等 不太可能起作用。相反,您可以检查到航路点的距离是否小于 Time.deltaTime * enemy.enemy.easySpeedMovement
,如果是,则不使用 Vector3.MoveTowards
,只需将位置准确设置为航路点,并将该步骤视为具有到达航路点。
这是粗略的逻辑(伪代码)(但不像我第一次写的那样伪代码):
Vector3 lastPos;
int waypointIndex;
void Start()
{
lastPos = gameObject.transform.position;
waypointIndex = 0;
}
void Update()
{
if (waypointIndex < waypoints.Count)
{
waypointPosition = new Vector3 (lastPos.x + waypoints.x, 0f, lastPos.z + waypoints.z);
if (Vector3.Distance(gameObject.transform.position, waypointPosition) > length of one step)
{
gameObject.transform.position = Vector3.MoveToward(gameObject.transform.position, waypointPosition);
}
else
{
gameObject.transform.position = waypointPosition;
log("Waypoint reached");
waypointIndex++;
}
}
}
使用Vector3.sqrMagnitude比较接近度。您可以定义 "close" 如何足够接近。在此示例中,我将使用航路点作为 Vector3
。您可以根据自己的喜好确定航路点Vector3
。
// define this globally
public float closeEnough = 5f;
// Within your compare method
if((gameObject.transform.position - waypoint).sqrMagnitude < closeEnough)
{
Debug.Log("waypoint reached");
}
注意:Vector3 - Vector3
的结果是另一个 Vector3
。
我遇到了这个问题:我需要敌人向目标位置移动,但我的问题是我在 Update 函数中写了这个,所以 "foreach" 语句只在一帧内完成。此外,"waypoint is reached" 语句从未显示。我该如何解决这个问题?
这是代码:`public class WayPointMovement : MonoBehaviour {
public EnemyDataSpawn enemy;
private Vector3 lastPos;
void Start ()
{
lastPos = gameObject.transform.position;
}
void Update ()
{
gameObject.transform.LookAt (LevelManager.current.playerObject.transform);
//WaypointData is a scriptable object that contains the definition of "x" and "z" coordinates.
foreach (WaypointData waypoints in enemy.enemy.waypoint) {
Debug.Log (waypoints.x);
gameObject.transform.position = Vector3.MoveTowards (gameObject.transform.position, new Vector3 (lastPos.x + waypoints.x, 0f, lastPos.z + waypoints.z), Time.deltaTime * enemy.enemy.easySpeedMovement);
if (gameObject.transform.position.x == lastPos.x + waypoints.x && gameObject.transform.position.z == lastPos.z + waypoints.z) {
Debug.Log("waypoint reached");
lastPos = gameObject.transform.position;
}
}
}
}`
您需要返工 Update
以便它只完成一帧的工作。这意味着您必须记住 a) 您要前往哪个航路点,以及 b) 您已经走了多远。只有当您真正到达下一个航路点时,您才会继续前进。
通过waypoints有两种追踪进度的方式:
1.一旦达到,您可以简单地删除 waypoints。然后,您尝试到达的航路点始终是列表中的第一个。
2。如果你想保留 waypoints,那么你需要一个额外的变量来跟踪 你当前 前往哪个 航路点。这可能类似于数组或列表的索引,或者它可能是一个枚举器 (IEnumerator<WaypointData>
),每次完成一个航路点时,您都会在其上调用 MoveNext
。
您已表明(在对此答案的评论中)您不想在到达时删除 waypoints。最灵活的安排是使用索引变量:
int waypointIndex;
void Start()
{
waypointIndex = 0;
}
void Update()
{
if (waypointIndex < waypoints.Count)
{
update position;
if (reached waypoint)
{
waypointIndex++;
}
}
}
然后,在您的 Update
方法中,您无需编写循环,而是仅更新一次游戏对象的位置,检查它是否仅到达过路点一次,如果已到达,则继续返回前的下一个航路点。如果需要多次移动才能到达一个航路点,您可以多次调用 Update
;每个Update
只是运动的一步。
您将需要更好的逻辑来确定何时到达航路点。正如其他评论者所指出的那样,对于浮点值,简单地检查它们是否 完全相等 不太可能起作用。相反,您可以检查到航路点的距离是否小于 Time.deltaTime * enemy.enemy.easySpeedMovement
,如果是,则不使用 Vector3.MoveTowards
,只需将位置准确设置为航路点,并将该步骤视为具有到达航路点。
这是粗略的逻辑(伪代码)(但不像我第一次写的那样伪代码):
Vector3 lastPos;
int waypointIndex;
void Start()
{
lastPos = gameObject.transform.position;
waypointIndex = 0;
}
void Update()
{
if (waypointIndex < waypoints.Count)
{
waypointPosition = new Vector3 (lastPos.x + waypoints.x, 0f, lastPos.z + waypoints.z);
if (Vector3.Distance(gameObject.transform.position, waypointPosition) > length of one step)
{
gameObject.transform.position = Vector3.MoveToward(gameObject.transform.position, waypointPosition);
}
else
{
gameObject.transform.position = waypointPosition;
log("Waypoint reached");
waypointIndex++;
}
}
}
使用Vector3.sqrMagnitude比较接近度。您可以定义 "close" 如何足够接近。在此示例中,我将使用航路点作为 Vector3
。您可以根据自己的喜好确定航路点Vector3
。
// define this globally
public float closeEnough = 5f;
// Within your compare method
if((gameObject.transform.position - waypoint).sqrMagnitude < closeEnough)
{
Debug.Log("waypoint reached");
}
注意:Vector3 - Vector3
的结果是另一个 Vector3
。