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

为什么Unity中使用MoveTowards时角色会逐渐减速最终停止移动?

问题根因
  • 协程执行逻辑理解错误:StartCoroutine不会阻塞后续代码执行,原代码中启动移动协程后立刻将turn设为false,会导致回合逻辑误判移动已完成,快速触发新的回合,短时间内启动大量重复的移动协程
  • 多协程位置控制冲突:多个同时运行的移动协程会同时修改角色位置,不同协程的目标点可能存在差异,导致移动速度被抵消,出现减速、无法移动的问题
  • 缺少协程生命周期管理:没有在启动新协程前终止旧的移动协程,冗余协程持续占用逻辑资源
修复方案
  • 将turn = false移动到协程内部,等待移动逻辑完全执行完成后再修改回合状态
  • 用成员变量记录当前运行的移动协程,每次启动新协程前先终止旧协程,保证同一时间只有一个移动协程在运行
  • 可选优化:用sqrMagnitude替代magnitude判断距离,减少性能消耗;提取移动速度为公共变量方便调整
修复后代码
// 移动速度提取为公共变量方便调整
public float moveSpeed = 0.3f;
private Coroutine moveCoroutine;

void Update()
{
    if (turn == true)
    {
        Move();
    }
}

void Move() 
{
    // 启动新协程前先停止之前的移动协程,避免多协程冲突
    if (moveCoroutine != null)
    {
        StopCoroutine(moveCoroutine);
    }
    
    Vector3 targetPos = target.transform.position;
    moveCoroutine = StartCoroutine(MoveOverTime(targetPos));

    IEnumerator MoveOverTime(Vector3 pos) 
    {
        // 用sqrMagnitude代替magnitude,性能更好,平方阈值对应原0.1的平方即0.01
        while ((transform.position - pos).sqrMagnitude > 0.01f)
        {
            transform.position = Vector3.MoveTowards(transform.position, pos, moveSpeed * Time.deltaTime);
            yield return null;
        }
        // 移动完成后再修改回合状态
        turn = false;
        // 协程执行完成后置空记录变量
        moveCoroutine = null;
    }
}
额外注意事项
  • 如果角色挂载了Rigidbody组件,不要直接修改transform.position,换成rigidbody.MovePosition()方法,避免和物理引擎计算产生冲突
  • 如果目标点在移动过程中会动态变化,可以根据需求调整是否需要实时更新协程内的目标位置参数

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.29 17:09:02