Unity:使用Translate与IEnumerator移动GameObject抖动问题排查
问题:鸟巢移动抖动且定时延迟仅生效一次
我正在制作一款简单的投篮类游戏,玩法是将鸡蛋投入移动的鸟巢中。尝试通过Translate方法移动GameObject,结合随机大小和方向的向量,让鸟巢在两个固定位置间定时随机移动。但测试时鸟巢出现原地抖动,且延迟仅在游戏启动时生效。
推测问题可能与Update方法持续调用协程有关,但不清楚为何会引发抖动及修复方式。以下是功能代码:
using System.Collections; using System.Collections.Generic; using UnityEngine; public class MoveNest : MonoBehaviour { public bool gameStarted = true; public float delay = 4; public float nestMoveSpeed = 1; public Vector3 nestMoveDirection = Vector3.zero; private int zBound = 8; // Start is called before the first frame update void Start() { } // Update is called once per frame void Update() { if (gameStarted) { StartCoroutine("ChangeMoveDirection"); transform.Translate(nestMoveDirection * Time.deltaTime * nestMoveSpeed); } } IEnumerator ChangeMoveDirection() { yield return new WaitForSeconds(delay); float minValue = 0; float maxValue = 0; if (transform.position.z >= zBound) { minValue = -10; maxValue = 0; } else if (transform.position.z <= -zBound) { minValue = 0; maxValue = 10; } else { minValue = -10; maxValue = 10; } nestMoveDirection = new Vector3(0, 0, Random.RandomRange(minValue, maxValue)); } }
问题原因
- 协程重复启动:Update方法每帧都会调用
StartCoroutine("ChangeMoveDirection"),短时间内生成大量协程实例。当这些协程到达延迟时间后,会频繁修改nestMoveDirection,方向随机切换导致抖动。 - 方向向量未归一化:随机生成的-10到10的z轴向量大小不稳定,造成移动速度忽快忽慢,加剧抖动。
- 定时逻辑失效:大量协程堆积导致后续定时触发完全混乱,仅初始延迟生效。
修复方案
- 仅启动一个协程实例,在内部循环执行方向变更逻辑,避免重复启动。
- 对随机方向向量归一化,保证移动速度稳定。
- 优化边界检测,强制限制鸟巢在指定范围内移动。
修复后的代码
using System.Collections; using System.Collections.Generic; using UnityEngine; public class MoveNest : MonoBehaviour { public bool gameStarted = true; public float delay = 4; public float nestMoveSpeed = 1; private Vector3 nestMoveDirection = Vector3.zero; private int zBound = 8; void Start() { // 游戏启动时仅启动一次循环协程 if (gameStarted) { StartCoroutine(ChangeMoveDirectionLoop()); } } void Update() { if (gameStarted) { transform.Translate(nestMoveDirection * Time.deltaTime * nestMoveSpeed); // 强制限制位置在边界内 ClampPosition(); } } // 循环执行方向变更的协程 IEnumerator ChangeMoveDirectionLoop() { while (gameStarted) { yield return new WaitForSeconds(delay); float minValue = 0; float maxValue = 0; if (transform.position.z >= zBound) { minValue = -1f; maxValue = 0f; } else if (transform.position.z <= -zBound) { minValue = 0f; maxValue = 1f; } else { minValue = -1f; maxValue = 1f; } // 生成归一化的随机方向,保证速度稳定 float randomZ = Random.Range(minValue, maxValue); nestMoveDirection = new Vector3(0, 0, randomZ).normalized; } } // 限制鸟巢位置在z轴边界内 void ClampPosition() { Vector3 newPos = transform.position; newPos.z = Mathf.Clamp(newPos.z, -zBound, zBound); transform.position = newPos; } }
关键修改点
- 改用循环协程
ChangeMoveDirectionLoop,仅在Start中启动一次,避免协程堆积。 - 随机方向范围改为-1到1,归一化后保证移动速度始终与
nestMoveSpeed一致。 - 添加
ClampPosition方法,强制限制鸟巢位置,防止超出边界。 - 移除Update中的协程启动代码,避免每帧重复触发。
内容的提问来源于stack exchange,提问作者DTD
相关产品推荐
相关产品推荐

