解释Tick与FixedTime的同步策略
解读
在国内 Unity 面试中,这道题考察的是“帧逻辑与物理逻辑如何互不干扰又保持确定性”。
面试官想确认:
- 你能否区分 Update 的 Tick(可变帧间隔) 与 FixedUpdate 的 FixedTime(固定 0.02 s 间隔) 的本质差异;
- 当两者节奏不同步时,你如何通过 插值、累积、预测 等手段让表现层与物理层看起来“严丝合缝”;
- 你是否能在 移动端 90 Hz/120 Hz 高刷屏 与 低端机 30 Hz 之间给出兼顾性能与手感的方案。
答不出“插值”或“回滚”关键词,基本会被判定为只写过 Demo。
知识点
-
时间轴
- Update 的 Time.deltaTime 每帧真实可变,受 VSync、GPU 阻塞、卡顿影响。
- FixedUpdate 的 Time.fixedDeltaTime 在 Project Settings 里写死,默认 0.02 s,Unity 通过 运行期累加“物理时钟” 决定是否补跑多轮 FixedUpdate。
-
同步策略三板斧
- 表现层插值(Interpolation):刚体勾选 interpolate,Unity 在渲染帧用 lastPos + (pos-lastPos) * (Time.time – fixedTime) / fixedDeltaTime 做线性插值,消除“抖动”。
- 预测外推(Extrapolation):若刚体速度可信且网络延迟低,可用 velocity * (Time.time – fixedTime) 外推,减少输入延迟;国内格斗、篮球项目常用 4~6 帧外推。
- 手动时间银行(Accumulator):自定义循环 while(accumulator >= fixedDeltaTime) { Simulate(fixedDeltaTime); accumulator -= fixedDeltaTime; },把剩余尾数留给下一帧,保证 物理步长绝对固定,同时把最大步数 clamp 到 3,防止低端机卡顿时“雪崩”。
-
热更新与确定性
- 使用 HybridCLR 或 il2cpp + Lua 时,物理层必须跑在 C# 主工程,热更脚本只能改表现或下发速度参数,否则不同客户端 FixedUpdate 次数不一致会导致 战斗校验失败。
- 帧同步项目(腾讯、网易 MOBA)会把 fixedDeltaTime 设为 66.7 ms(15 Hz),逻辑层只认 StepIndex,渲染层用插值补到 60 FPS,既省 CPU 又保证 逐帧回放一致。
-
平台差异
- iOS 120 Hz 屏若直接开 120 FPS,物理默认 50 Hz 会出现“一帧插两次”的鬼畜;解决方法是把 fixedDeltaTime 降到 0.0111 s(90 Hz)或 0.0083 s(120 Hz),但步数翻倍,GPU 压力小的休闲项目才建议同步。
- Android 低端机卡顿 300 ms 时,Unity 会一次性补 15 步物理,刚体穿透、弹力爆炸;此时需在代码里 动态下调 Time.maximumDeltaTime 到 0.1 s,让步数 ≤5,牺牲一点慢动作,保证不穿模。
答案
“Unity 把真实时间拆成两条轨道:
- 可变帧渲染轨道——Update 的 Tick,以 GPU 实际刷新率为准;
- 固定步长物理轨道——FixedUpdate 的 FixedTime,以 Time.fixedDeltaTime 为节拍。
同步策略的核心是 ‘让眼睛看到平滑,让物理保持确定’:
- 引擎层:Unity 每帧先累加 Time.deltaTime 到‘物理时钟’,只要时钟 ≥ fixedDeltaTime 就循环调用 FixedUpdate,最多跑 3 步防止卡死;剩余尾数留到下一帧。
- 表现层:对刚体打开 interpolate,Unity 自动用上一帧物理结果做线性插值,把 50 Hz 的物理数据平滑到 60 Hz 甚至 120 Hz 的屏幕,玩家看不到抖动。
- 网络帧同步:把 fixedDeltaTime 调成 66.7 ms,逻辑只认 StepIndex,客户端本地再用插值补到渲染帧,既省流量又保证回放一致。
- 高刷适配:若项目 GPU 富裕,可把 fixedDeltaTime 降到 0.0111 s,让物理步数与 90 Hz 屏幕成整数倍,避免插值误差;若 GPU 紧张,则保持 50 Hz 物理,仅用插值上屏,不改动确定性核心。
一句话总结:用固定步长保证结果可复现,用插值/外推让肉眼感觉流畅,用 accumulator 上限与 maximumDeltaTime 防止低端机雪崩。”
拓展思考
- 如果项目使用 自定义物理引擎(如 DOTS-Physics),你仍需自己实现 accumulator 与插值,但可以利用 Unity 的 FixedStepSimulationSystemGroup,把物理世界与渲染世界彻底分离,并通过 IJobEntityBatch 并行插值,在 120 Hz 屏上零 GC 平滑。
- 对于 XR 应用,Unity 的 XR SDK 会额外插入 PredictionTime = 0.011 s 的头部预测;此时若物理仍用 50 Hz,手柄碰撞会出现“打到空气”的错位。经验是把 fixedDeltaTime 提到 72 Hz(Quest2 刷新率),并开启 Run In Background + FixedUpdate 外推,让碰撞体提前 1 帧到位。
- 在 数字孪生 场景,需要与 PLC 硬实时 10 ms 数据对齐,Unity 的默认 20 ms 不够;此时可改为 0.01 s,但要把 Maximum Allowed Timestep 压到 0.03 s,防止 Windows 笔记本休眠后一次性补 30 步导致刚体飞散。