在Unity中控制游戏角色移动速度的核心是 使用 Time.deltaTime 实现帧率无关移动——这是最基础也最关键的原则,确保角色在不同帧率设备(如30fps手机和60fps电脑)上移动速度一致。此外,还可通过 Time.timeScale 实现慢动作/快进移动,或用 Time.unscaledDeltaTime 实现不受暂停影响的移动(如UI角色、后台移动单位)。

以下分 核心实现(帧率无关移动)进阶控制(慢动作/暂停兼容)不同移动方式适配 三部分详细说明,附完整代码示例。

一、核心原则:为什么必须用 Time.deltaTime

  • 游戏的 Update() 函数调用频率不固定(帧率越高,调用越频繁);
  • Time.deltaTime 表示“上一帧到当前帧的时间间隔(秒)”,乘以移动速度后,能将“每帧移动距离”转换为“每秒移动距离”,实现 帧率无关

❌ 错误做法(帧率依赖,低帧率变慢):

// 假设60fps,每帧移动 5/60 米,但30fps时每帧仍移动同样距离,每秒仅移动 5/60 *30 = 2.5米(速度减半)
transform.Translate(Vector3.forward * 5f / 60f); 

✅ 正确做法(帧率无关,每秒稳定移动5米):

// 速度(米/秒)* 帧间隔(秒)= 每帧移动距离(米),无论帧率多少,每秒总距离=速度
transform.Translate(Vector3.forward * speed * Time.deltaTime); 

二、基础实现:帧率无关的角色移动(最常用)

适用于 普通角色移动(如PC端 WASD、移动端虚拟摇杆),核心是在 Update() 中用 Time.deltaTime 计算移动量。

1. 代码示例(Transform 直接移动,适合非物理角色)

适合2D/3D角色(如Top-Down视角、横版卷轴),无需物理碰撞(或用碰撞体+非刚体):

using UnityEngine;

public class PlayerMovement : MonoBehaviour
{
    [Header("移动配置")]
    public float moveSpeed = 5f; // 核心:移动速度(单位:米/秒,帧率无关)
    public bool useWorldSpace = true; // true=世界空间移动(固定前后左右),false=本地空间(跟随角色朝向)

    void Update()
    {
        // 1. 获取输入(PC端 WASD/方向键,可替换为移动端摇杆输入)
        float horizontal = Input.GetAxis("Horizontal"); // 左右:-1(左)~1(右)
        float vertical = Input.GetAxis("Vertical");     // 前后:-1(后)~1(前)
        
        // 2. 构建移动方向(归一化避免斜向移动过快)
        Vector3 moveDir = new Vector3(horizontal, 0, vertical).normalized;
        // (2D游戏替换为:Vector2 moveDir = new Vector2(horizontal, vertical).normalized;)

        // 3. 帧率无关移动(核心:乘以 Time.deltaTime)
        if (useWorldSpace)
        {
            // 世界空间移动(适合固定视角,如上帝视角)
            transform.Translate(moveDir * moveSpeed * Time.deltaTime);
        }
        else
        {
            // 本地空间移动(适合第三人称/第一人称,移动方向跟随角色朝向)
            transform.Translate(moveDir * moveSpeed * Time.deltaTime, Space.Self);
        }
    }
}

2. 代码示例(Rigidbody 物理移动,适合需要碰撞/重力的角色)

如果角色有 Rigidbody(3D)或 Rigidbody2D(2D),必须在 FixedUpdate() 中使用 Time.fixedDeltaTime(物理帧固定间隔,默认0.02秒),避免物理抖动:

using UnityEngine;

public class PlayerPhysicsMovement : MonoBehaviour
{
    [Header("物理移动配置")]
    public float moveSpeed = 5f; // 移动速度(米/秒)
    private Rigidbody rb; // 3D角色用Rigidbody,2D用Rigidbody2D

    void Start()
    {
        // 获取组件(确保角色身上已添加Rigidbody,且勾选"Use Gravity")
        rb = GetComponent<Rigidbody>();
        // 优化:锁定旋转(避免移动时角色倾倒)
        rb.freezeRotation = true;
    }

    // 物理逻辑必须用 FixedUpdate(固定时间步,不受帧率影响)
    void FixedUpdate()
    {
        // 1. 获取输入
        float horizontal = Input.GetAxis("Horizontal");
        float vertical = Input.GetAxis("Vertical");
        Vector3 moveDir = new Vector3(horizontal, 0, vertical).normalized;

        // 2. 物理移动(两种方式选一种)
        // 方式1:直接设置速度(适合匀速移动,不受摩擦力影响)
        rb.velocity = new Vector3(moveDir.x * moveSpeed, rb.velocity.y, moveDir.z * moveSpeed);

        // 方式2:施加力(适合有加速度/摩擦力的场景,需调整ForceMode)
        // rb.AddForce(moveDir * moveSpeed * Time.fixedDeltaTime, ForceMode.VelocityChange);
    }
}

关键说明:

  • moveSpeed 的单位是 米/秒(Unity默认单位),直观易调整(如想让角色1秒移动5米,就设为5);
  • 移动方向需 normalized:避免斜向移动时(如同时按W+D),向量长度为√2≈1.414,导致斜向速度比正向快。

三、进阶控制:用 Time.timeScale 调整移动速度(慢动作/快进)

Time.timeScale 是时间缩放因子,会影响 Time.deltaTimeTime.fixedDeltaTime,因此可直接控制移动速度的“时间流速”,实现慢动作、快进等效果。

1. 慢动作/快进示例

在基础移动代码上,只需修改 Time.timeScale,移动速度会自动按比例变化:

// 绑定到UI按钮的点击事件(示例:慢动作、正常、快进)
public void SetSlowMotion()
{
    Time.timeScale = 0.5f; // 移动速度变为原来的50%(慢动作)
}

public void SetNormalSpeed()
{
    Time.timeScale = 1f; // 正常速度
}

public void SetFastForward()
{
    Time.timeScale = 2f; // 移动速度变为原来的200%(快进)
}

2. 暂停时的特殊处理

Time.timeScale = 0(暂停)时,Time.deltaTime 会变为0,角色会停止移动。若需要 暂停时仍能移动的角色(如UI提示角色、后台巡逻的敌人),需用 Time.unscaledDeltaTime

// 暂停时仍能移动的角色(如UI角色)
public class UnscaledMovement : MonoBehaviour
{
    public float moveSpeed = 3f;

    void Update()
    {
        // 核心:用 Time.unscaledDeltaTime(不受 timeScale 影响)
        transform.Translate(Vector3.right * moveSpeed * Time.unscaledDeltaTime);
    }
}

注意事项:

  • 物理移动(Rigidbody)的暂停:除了 Time.timeScale = 0,还需设置 rb.isKinematic = true(暂停物理模拟),恢复时设为 false
  • 等待逻辑:若用 WaitForSeconds() 配合慢动作,等待时间会按 timeScale 缩放(如 timeScale=0.5 时,WaitForSeconds(2) 实际等4秒);若需实时等待,用 WaitForSecondsRealtime()

四、不同移动场景的适配

1. 2D角色移动(Rigidbody2D)

using UnityEngine;

public class Player2DMovement : MonoBehaviour
{
    public float moveSpeed = 5f;
    private Rigidbody2D rb2D;

    void Start()
    {
        rb2D = GetComponent<Rigidbody2D>();
        rb2D.freezeRotation = true;
    }

    void FixedUpdate()
    {
        float horizontal = Input.GetAxis("Horizontal");
        float vertical = Input.GetAxis("Vertical");
        Vector2 moveDir = new Vector2(horizontal, vertical).normalized;

        // 2D物理移动
        rb2D.velocity = moveDir * moveSpeed;
    }
}

2. 第一人称/第三人称移动(跟随相机方向)

让移动方向跟随相机视角(如按下W时向相机前方移动):

using UnityEngine;

public class PlayerCameraRelativeMovement : MonoBehaviour
{
    public float moveSpeed = 6f;
    public Camera mainCamera; // 赋值主相机

    void Update()
    {
        // 1. 获取输入
        float horizontal = Input.GetAxis("Horizontal");
        float vertical = Input.GetAxis("Vertical");
        Vector3 inputDir = new Vector3(horizontal, 0, vertical).normalized;
        if (inputDir.magnitude < 0.1f) return; // 无输入时退出

        // 2. 获取相机的水平旋转(忽略垂直旋转,避免上下看时移动方向倾斜)
        Quaternion cameraRot = Quaternion.Euler(0, mainCamera.transform.eulerAngles.y, 0);
        // 3. 将输入方向转换为相机空间
        Vector3 moveDir = cameraRot * inputDir;

        // 4. 帧率无关移动
        transform.Translate(moveDir * moveSpeed * Time.deltaTime);
    }
}

3. 加速/减速移动(动态调整 moveSpeed

通过 Time.time 或计时器实现速度渐变:

public class AcceleratedMovement : MonoBehaviour
{
    public float baseSpeed = 3f;
    public float acceleration = 2f; // 每秒增加的速度(米/秒²)
    public float maxSpeed = 8f;     // 最大速度上限

    void Update()
    {
        float horizontal = Input.GetAxis("Horizontal");
        float vertical = Input.GetAxis("Vertical");
        Vector3 moveDir = new Vector3(horizontal, 0, vertical).normalized;

        if (moveDir.magnitude > 0.1f)
        {
            // 加速:速度 = 基础速度 + 加速度 * 时间(帧率无关)
            moveSpeed = Mathf.MoveTowards(moveSpeed, maxSpeed, acceleration * Time.deltaTime);
        }
        else
        {
            // 无输入时减速到0
            moveSpeed = Mathf.MoveTowards(moveSpeed, 0, acceleration * 2 * Time.deltaTime);
        }

        transform.Translate(moveDir * moveSpeed * Time.deltaTime);
    }
}

五、常见问题排查

  1. 角色斜向移动过快:忘记对移动方向 normalized,导致斜向向量长度>1;
  2. 物理移动抖动:在 Update() 中操作Rigidbody,应改为 FixedUpdate() 并使用 Time.fixedDeltaTime
  3. 暂停后角色仍移动:误用了 Time.unscaledDeltaTime,需检查是否需要受 timeScale 影响;
  4. 不同设备速度不一致:未使用 deltaTime,或误将 fixedDeltaTime 用于 Update()

总结

控制角色移动速度的核心流程:

  1. 定义 moveSpeed(单位:米/秒),作为基础移动速度;
  2. Update()(Transform移动)或 FixedUpdate()(物理移动)中,获取输入并构建移动方向;
  3. Time.deltaTime(受时间缩放)或 Time.unscaledDeltaTime(不受时间缩放)乘以速度和方向,实现帧率无关移动;
  4. 进阶需求:通过 Time.timeScale 控制慢动作/快进,或动态调整 moveSpeed 实现加速/减速。

按以上方法,可确保角色在任何设备、任何帧率下都能按预期速度移动,且兼容暂停、慢动作等常见游戏机制。