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

Unity使用Time.deltaTime后玩家移动仍存在帧率依赖问题

问题根因

你遇到的帧率不稳定问题核心原因是线性缩放deltaTime的方式不适用于指数型的速度衰减逻辑:
Scratch默认以30fps固定步长运行,每帧执行vx = vx * Decceleration的减速逻辑,本质是固定时间步长下的指数衰减过程。你当前用Velocity.x -= Velocity.x*(1-Decceleration) * SDT()的写法是对衰减过程的一阶线性近似,当帧时间和30fps的标准帧时长(1/30秒)偏差越大,近似误差越高,最终就会出现最高速度随帧率浮动的问题。
另外所有运动、速度更新逻辑放在Update中执行,Update的调用间隔随渲染帧率波动,本身就容易带来物理模拟的不稳定。

修复方案
  • 修正减速逻辑的时间缩放方式
    将线性近似的减速计算替换为指数形式的时间缩放,完全匹配不同帧率下的衰减效果:

    // 替换原来的 Velocity.x -= Velocity.x*(1-Decceleration) * SDT();
    float decayPerScratchFrame = Decceleration; // 原Scratch中每30fps帧的速度保留比例
    Velocity.x *= Mathf.Pow(decayPerScratchFrame, SDT());
    

    原理:指数衰减的通用公式为v(t) = v0 * r^(t/t0),其中t0是原始固定步长(这里是1/30秒),r是原始步长下的衰减系数,t是当前帧的实际时长,用Pow计算可以保证任意帧时长下,累计衰减效果和30fps固定步长完全一致。

  • 统一运动逻辑的更新时机
    将所有速度计算、运动更新逻辑从Update迁移到FixedUpdate,使用Time.fixedDeltaTime替代Time.deltaTime做时间计算,从根源上避免帧间隔波动带来的模拟误差:

    • 把Application.targetFrameRate = TargetFPS;移动到Start()方法中调用,不需要每帧设置
    • 修改SDT()方法适配固定时间步长
    • 修改Move方法中的时间缩放,使用Time.fixedDeltaTime
  • 输入检测适配
    输入检测不要放在FixedUpdate中(避免输入漏检),可以在Update中缓存输入状态,在FixedUpdate中使用缓存的状态计算速度。

修复后完整参考代码
using System.Collections.Generic;
using UnityEngine;

public class PlayerMovement : MonoBehaviour
{
    public Vector2 Velocity, WallJumpForce;
    public float Acceleration, Decceleration;
    public float Gravity, JumpForce;
    public int TargetFPS = 60;
    private float _inputX;

    void Start()
    {
        Application.targetFrameRate = TargetFPS;
    }

    void Update()
    {
        // 仅在Update中缓存输入,避免FixedUpdate频率不匹配导致的输入漏检/重复检测
        _inputX = 0;
        if(Input.GetKey("right") || Input.GetKey("d"))
            _inputX += 1;
        if(Input.GetKey("left") || Input.GetKey("a"))
            _inputX -= 1;
    }

    void FixedUpdate()
    {
        // 所有物理/速度计算放在FixedUpdate中,使用固定时间步长
        Velocity.y -= Gravity * SDT();
        Velocity.x += Acceleration * _inputX * SDT();
        // 修正后的指数衰减减速逻辑
        Velocity.x *= Mathf.Pow(Decceleration, SDT());
        
        Move(Velocity.x, Velocity.y);
    }

    void Move(float x, float y) //Converts Scratch Units to Unity Units
    {
        transform.position += new Vector3(x, y, 0) * 1.2f * Time.fixedDeltaTime;
    }
    
    float SDT() // 将Scratch 30fps下的逻辑参数适配到Unity时间步长
    {
        return 30 * Time.fixedDeltaTime;
    }
}
验证说明

修复后无论帧率设置为30、60还是更高/更低,X轴最大速度都会稳定在设计值6.75,不会再出现随帧率浮动到7.5的问题,同时重力、跳跃等其他和时间相关的逻辑也会保持帧率无关的一致性。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.02 08:12:47