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

Unity中Rigidbody.velocity拖拽玩家移动不流畅,如何实现Transform.Position般顺滑?

用Rigidbody实现顺滑拖拽移动的解决方案

嘿,我完全懂你的困扰——直接改Transform.position确实顺滑到飞起,但没法处理碰撞;换成Rigidbody.velocity后移动就变得卡顿生硬,太闹心了。核心问题其实是输入更新和物理更新的时机不匹配,加上直接操作velocity的方式不符合物理引擎的工作逻辑。下面给你几个靠谱的解决办法:

为什么Rigidbody移动会不流畅?

  • Update()是每帧执行,帧率会随设备性能波动;而物理引擎的更新是在FixedUpdate()里,时间步长是固定的(默认0.02秒)。如果在Update()里直接操作Rigidbody,会导致物理计算和输入不同步,出现卡顿。
  • 直接设置velocity会让物理引擎的其他力(比如摩擦力、碰撞反馈)干扰你的移动指令,破坏原本的顺滑感。

最优解决方案:用Rigidbody.MovePosition

这个方法专门为「让刚体跟随目标位置移动」的场景设计,它会自动处理物理约束(碰撞、重力),同时保持移动的平滑性。具体步骤如下:

  1. 在Update()中记录触摸的移动增量(输入事件只有在Update()里能准确捕获)
  2. 在FixedUpdate()中使用Rigidbody.MovePosition执行物理移动,结合固定时间步长保证速度一致

修改后的完整代码

private Rigidbody rb;
private Vector3 touchMovementDelta;
public float speedModifier = 0.1f;

void Start()
{
    // 获取刚体组件,记得给玩家对象添加Rigidbody哦
    rb = GetComponent<Rigidbody>();
    // 关键:开启刚体插值,消除物理帧和渲染帧不同步的抖动
    rb.interpolation = RigidbodyInterpolation.Interpolate;
}

void Update()
{
    touchMovementDelta = Vector3.zero;
    
    if(Input.touchCount > 0)
    {
        Touch touch = Input.GetTouch(0);
        if(touch.phase == TouchPhase.Moved)
        {
            // 将屏幕触摸的delta转换为世界空间的移动量
            // 2D游戏可以调整轴的对应关系,比如把z换成y
            touchMovementDelta = new Vector3(
                touch.deltaPosition.x * speedModifier,
                0,
                touch.deltaPosition.y * speedModifier);
        }
    }
}

void FixedUpdate()
{
    // 计算目标位置:当前刚体位置 + 移动增量 * 固定时间步长(保证帧率无关)
    Vector3 targetPosition = rb.position + touchMovementDelta * Time.fixedDeltaTime;
    
    // 使用MovePosition移动刚体,物理引擎会自动处理碰撞和平滑插值
    rb.MovePosition(targetPosition);
}

几个关键优化点

  • 开启Rigidbody的Interpolate选项:这个设置会让刚体在渲染帧之间做插值,彻底消除物理更新和渲染帧不同步导致的微小抖动。
  • 用Time.fixedDeltaTime缩放移动量:确保不管设备帧率如何变化,移动速度都是一致的,不会出现时快时慢的情况。
  • 输入和移动分离:输入在Update()捕获,移动在FixedUpdate()执行,完美贴合Unity的事件循环逻辑。

如果你非要用velocity的话...

如果因为某些场景限制必须用velocity,可以这样优化,但还是不如MovePosition稳定:

void FixedUpdate()
{
    if(touchMovementDelta != Vector3.zero)
    {
        // 计算目标速度,用fixedDeltaTime保证帧率无关
        Vector3 targetVelocity = touchMovementDelta / Time.fixedDeltaTime;
        // 保留Y轴速度(比如重力),只修改XZ轴
        targetVelocity.y = rb.velocity.y;
        // 设置刚体速度
        rb.velocity = targetVelocity;
    }
    else
    {
        // 触摸停止时,清零XZ轴速度,避免刚体继续滑动
        rb.velocity = new Vector3(0, rb.velocity.y, 0);
    }
}

这个方法在复杂碰撞场景下还是容易出现速度突变,所以优先推荐MovePosition方案。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.08 12:47:33