如何在Timeline中让某轨道忽略timeScale

解读

国内项目普遍用 Timeline 做剧情、技能、UI 动效,策划经常要求“暂停按钮不能把演出全停掉”,本质就是部分轨道要无视 Time.timeScale。如果候选人只答“把 timeScale 改回 1”会被直接判负,因为那会破坏全局暂停逻辑;正确思路是让轨道自己驱动时间,而不是依赖 Unity 的全局时间。面试官想听你能否在不改引擎源码的前提下,用官方开放接口把“轨道时间”和“游戏时间”解耦,并兼顾编辑器预览、运行时热更、移动端性能。

知识点

  1. PlayableGraph 的 UpdateMode:DSP、GameTime、UnscaledGameTime、Manual
  2. TrackAsset 的 CreateTrackMixer 返回自定义 PlayableBehaviour,可重写 PrepareFrameProcessFrame
  3. Playable.GetTimeSetTime 是轨道内部时间,Director.time 受 timeScale 影响
  4. IPlayableBehaviour.GetMixerTime 可拿到 Director 的 unscaled 时间:
    var unscaled = (float)playable.GetGraph().GetResolver().GetTimeUpdateMode() == DirectorUpdateMode.Manual ? Time.unscaledTime : Director.time / Time.timeScale * Time.unscaledTime;
  5. 自定义 Clip PlayableBehaviour 里缓存进入时的 unscaledTime,后续帧用 Time.unscaledTime - enterTime 做本地时钟
  6. Build 时打宏 #if UNITY_EDITOR 区分编辑器预览与真机,防止编辑器下误用 unscaledTime 导致 scrub 失效
  7. 热更框架(HybridCLR/ILRuntime) 下,自定义 PlayableBehaviour 必须生成绑定代码,否则裁剪后反射找不到类型

答案

  1. 新建一个 IgnoreTimeScaleTrack 继承 TrackAsset,重写
    public override Playable CreateTrackMixer(PlayableGraph graph, GameObject go, int inputCount)
    返回自定义 IgnoreTimeScaleMixerBehaviour
  2. IgnoreTimeScaleMixerBehaviour 实现 IPlayableBehaviour
    • PrepareFrame 里用 Time.unscaledTime 计算本地时钟 m_UnscaledTime
    • 遍历所有 input clip,调用 playable.GetInput(i).SetTime(m_UnscaledTime),把本地时间写进每个 clip 的 playable
    • 返回 true,告诉 graph 使用自定义时间
  3. 对 clip 端,如果自带动画(AnimationPlayable),在 ProcessFrame 里把权重设为 1,强制采样 animationPlayable.SetTime(m_UnscaledTime)
  4. 把轨道上的 UpdateMode 设为 DSPManual,防止 Director 的 deltaTime 被 timeScale 缩放
  5. 真机测试:在 Update 里临时把 timeScale 设为 0,确认角色特效、UI 粒子继续播放;Profiler 中观察 PlayableGraph.Evaluate 耗时,确保移动端 < 0.3 ms

一句话总结:在 TrackMixer 里用 Time.unscaledTime 重写 playable 的本地时间,完全绕开 Director 的 timeScale

拓展思考

  1. 部分忽略需求:如果只想忽略 50% 的 timeScale,可在 PrepareFrame 里做 lerp(Director.time, unscaledTime, weight),让策划在 Timeline 窗口直接调曲线
  2. 网络帧同步:在帧同步战斗里,服务器发帧号,客户端把帧号转成 unscaledTime,保证技能 Timeline 在断网暂停时继续走完收刀动作
  3. 音频轨道:AudioTrack 内部用 FMOD,不受 timeScale 影响,但若用 AudioMixer 做快照,需要把 AudioSource.pitch 同步到 1/timeScale,否则会出现音画不同步
  4. WebGL 限制:WebGL 的 Time.unscaledTime 精度只有 1 ms,高频演出需改用 AudioSettings.dspTime 做主时钟,否则 120 fps 下会出现抖动