You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Unity中Vector3.MoveTowards正常但Vector2.MoveTowards失效的原因

问题:Unity 2D中Vector2.MoveTowards导致敌人卡在首个路点,Vector3却正常工作

我在Unity 2021.3的2D环境中搭建基于路点的敌人寻路系统,将EnemyPathing.cs脚本挂载到敌人预制体上。当使用Vector2.MoveTowards实现移动时,敌人卡在首个路点(waypointIndex[0])无法切换到下一个路点;但使用Vector3.MoveTowards时则能正常工作。核心代码如下:

public class EnemyPathing : MonoBehaviour 
{ 
    [SerializeField] List<Transform> waypoints; 
    [SerializeField] float moveSpeed = 2f; 
    int waypointIndex = 0;

    void Start()
    {
        transform.position = waypoints[waypointIndex].transform.position;
    }

    void Update()
    {
        Move();
    }

    private void Move()
    {
        if (waypointIndex <= waypoints.Count - 1)
        {
            var targetPosition = waypoints[waypointIndex].transform.position;
            var movementThisFrame = moveSpeed * Time.deltaTime;
            // 问题代码
            transform.position = Vector2.MoveTowards(transform.position, targetPosition, movementThisFrame);
            if (transform.position == targetPosition)
            {
                waypointIndex++;
            }
        }
        else
        {
            Destroy(gameObject);
        }
    }
}

原因分析

1. Vector2与Vector3类型转换导致Z轴不一致

transform.position是Vector3类型,包含X/Y/Z三个轴的值。使用Vector2.MoveTowards时,会自动将输入的Vector3转换为Vector2(丢弃Z轴),计算后返回的Vector2再隐式转换回Vector3赋值给transform.position——此时Z轴会被强制重置为0。

如果你的路点Transform的Z轴值不为0(比如2D场景中为分层设置了Z轴偏移),那么transform.position的Z轴是0,而targetPosition的Z轴是路点的原始值,两者永远无法相等,导致waypointIndex无法递增,敌人卡在第一个路点。

而Vector3.MoveTowards会直接操作三个轴的数值,保持Z轴与当前物体一致,当路点Z轴和敌人初始Z轴相同时,移动后两者Z轴相等,更容易满足transform.position == targetPosition的判断。

2. 浮点数精度误差的隐形影响

即使路点Z轴为0,直接用==比较两个Vector3/Vector2也可能因为浮点数运算的精度问题导致判断失败。比如移动步长movementThisFrame可能让物体停在离目标极近但不完全相等的位置,这时==会返回false。Vector3.MoveTowards因为直接操作三个轴,可能在某些场景下刚好让位置完全匹配,而Vector2的转换可能放大了这种精度误差。

解决方案

方案一:转换为Vector2后再比较

将位置判断改为基于Vector2的比较,忽略Z轴的影响:

private void Move()
{
    if (waypointIndex <= waypoints.Count - 1)
    {
        var targetPosition = waypoints[waypointIndex].transform.position;
        var movementThisFrame = moveSpeed * Time.deltaTime;
        transform.position = Vector2.MoveTowards(transform.position, targetPosition, movementThisFrame);
        // 转换为Vector2后比较,忽略Z轴
        if ((Vector2)transform.position == (Vector2)targetPosition)
        {
            waypointIndex++;
        }
    }
    else
    {
        Destroy(gameObject);
    }
}

方案二:使用距离阈值判断(推荐)

避免直接用==比较浮点数,而是判断当前位置与目标位置的距离是否小于一个极小的阈值(比如0.01f),彻底解决精度问题:

private void Move()
{
    if (waypointIndex <= waypoints.Count - 1)
    {
        var targetPosition = waypoints[waypointIndex].transform.position;
        var movementThisFrame = moveSpeed * Time.deltaTime;
        transform.position = Vector2.MoveTowards(transform.position, targetPosition, movementThisFrame);
        // 用距离阈值替代直接相等判断
        if (Vector2.Distance(transform.position, targetPosition) < 0.01f)
        {
            waypointIndex++;
        }
    }
    else
    {
        Destroy(gameObject);
    }
}

方案三:统一处理Z轴

如果需要保留Z轴的层级设置,可以手动将目标位置的Z轴设置为与当前物体一致,再使用Vector2.MoveTowards:

private void Move()
{
    if (waypointIndex <= waypoints.Count - 1)
    {
        var targetPos = waypoints[waypointIndex].transform.position;
        // 保持Z轴与当前物体一致
        var targetPosition2D = new Vector2(targetPos.x, targetPos.y);
        var currentPos2D = new Vector2(transform.position.x, transform.position.y);
        
        var newPos2D = Vector2.MoveTowards(currentPos2D, targetPosition2D, moveSpeed * Time.deltaTime);
        // 重新赋值时保留原Z轴
        transform.position = new Vector3(newPos2D.x, newPos2D.y, transform.position.z);
        
        if (Vector2.Distance(currentPos2D, targetPosition2D) < 0.01f)
        {
            waypointIndex++;
        }
    }
    else
    {
        Destroy(gameObject);
    }
}

内容的提问来源于stack exchange,提问作者Shaker

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.02 07:15:26