Unity:如何用Vector2.Lerp慢速移动物体?函数内延时需用协程吗?
Unity中Vector2.Lerp移动物体与延时执行的实现方案
一、用Vector2.Lerp实现慢速移动
Vector2.Lerp(a, b, t)的作用是在a、b两点间做线性插值,t取值范围为[0,1]。要实现平滑慢速移动,核心是让t随时间逐步递增,而非直接设为1(否则会瞬间到位)。
常见两种实现逻辑:
- 匀速移动:记录起始位置、目标位置和总移动时长,每帧根据已消耗时间计算
t的比例 - 平滑减速移动:每帧以当前位置为起点向目标插值,
t设为固定小值乘以Time.deltaTime,越靠近目标移动越慢
二、延时/逐帧执行的替代方案(并非必须用协程)
协程是Unity处理这类逻辑的标准方案,但如果觉得繁琐,也可以用以下几种方式:
1. 状态标记+Update逐帧处理
在类中添加状态变量标记是否处于移动状态,然后在Update中处理移动进度:
private bool _isMoving = false; private Vector2 _startPos; private Vector2 _targetPos; private float _moveDuration = 1f; // 移动总时长 private float _elapsedTime = 0f; void Update() { RaycastHit2D hitPlayer = Physics2D.Raycast(_tr.position, new Vector2(-1,0), _distance, LayerMask.GetMask("Player")); if (hitPlayer.collider != null && Input.GetKeyDown(KeyCode.Space) && !_isMoving) { MovingToBox(hitPlayer); } // 处理移动逻辑 if (_isMoving) { _elapsedTime += Time.deltaTime; float t = Mathf.Clamp01(_elapsedTime / _moveDuration); _tr.position = Vector2.Lerp(_startPos, _targetPos, t); // 移动完成后重置状态 if (t >= 1f) { _isMoving = false; } } } private void MovingToBox(RaycastHit2D hitPlayer) { _startPos = _tr.position; _targetPos = hitPlayer.transform.position; // 可根据需求调整目标位置 _isMoving = true; _elapsedTime = 0f; }
2. 简洁的协程写法
其实协程并没有想象中繁琐,配合yield return可以快速实现逐帧逻辑:
void Update() { RaycastHit2D hitPlayer = Physics2D.Raycast(_tr.position, new Vector2(-1,0), _distance, LayerMask.GetMask("Player")); if (hitPlayer.collider != null && Input.GetKeyDown(KeyCode.Space)) { StartCoroutine(MovingToBoxCoroutine(hitPlayer)); } } private IEnumerator MovingToBoxCoroutine(RaycastHit2D hitPlayer) { Vector2 startPos = _tr.position; Vector2 targetPos = hitPlayer.transform.position; float duration = 1f; float elapsedTime = 0f; while (elapsedTime < duration) { elapsedTime += Time.deltaTime; float t = Mathf.Clamp01(elapsedTime / duration); _tr.position = Vector2.Lerp(startPos, targetPos, t); yield return null; // 等待下一帧 } // 确保最终位置精准到位 _tr.position = targetPos; }
3. 无时长限制的平滑减速移动
如果不需要严格控制移动时长,只是要平滑靠近目标,可使用这种简化写法:
private bool _isMoving = false; private Vector2 _targetPos; private float _smoothSpeed = 2f; // 控制移动快慢,值越大速度越快 void Update() { RaycastHit2D hitPlayer = Physics2D.Raycast(_tr.position, new Vector2(-1,0), _distance, LayerMask.GetMask("Player")); if (hitPlayer.collider != null && Input.GetKeyDown(KeyCode.Space) && !_isMoving) { _targetPos = hitPlayer.transform.position; _isMoving = true; } if (_isMoving) { _tr.position = Vector2.Lerp(_tr.position, _targetPos, _smoothSpeed * Time.deltaTime); // 当距离足够近时停止移动 if (Vector2.Distance(_tr.position, _targetPos) < 0.01f) { _tr.position = _targetPos; _isMoving = false; } } }
关键注意点
- 实现匀速移动时,必须记录初始起始位置,不能每帧用当前位置作为Lerp的第一个参数,否则会变成减速移动
Mathf.Clamp01可确保t不会超过1,避免物体越过目标位置- 如果需要更复杂的运动曲线(如先加速后减速),可以用
AnimationCurve来控制t的变化
内容的提问来源于stack exchange,提问作者Nikolay
相关产品推荐
相关产品推荐

