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

