为什么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
相关产品推荐
相关产品推荐

