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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.25 23:48:21