# 背景
根据策划需求要在剧情中加入战斗,战斗结束后继续播放剧情。我添加了自定义 clip 去调用战斗系统。但是进入战斗时严重掉帧导致两帧跨越了一个 clip. 导致数据和表现全部错乱,甚至如果是 timeline 末尾进入战斗会导致 timeline 直接结束 OnBehaviourPause 并未调用导致我的暂停功能失效.
# 解决方案
修改 Playable Director 上的 update Method 为 Manual. 采用脚本手动控制。我自己是放在 fixedUpdate 中了.
改完然后发现 timeline 自带的的 audio 和 Single 全部失效了。我又全部手动实现了一下。如下是 single 的实现 (audio 也类似就不写了):
public PlayableDirector director; | |
private SignalReceiver _signalReceiver; | |
private List<SignalEmitterInfo> signalEmitters = new List<SignalEmitterInfo>(); | |
private Dictionary<AudioSource, List<AudioInfo>> audioInfoDic = new Dictionary<AudioSource, List<AudioInfo>>(); | |
class SignalEmitterInfo | |
{ | |
public SignalEmitter signalEmitter; | |
public bool isInvoke = false; | |
public SignalEmitterInfo(SignalEmitter signalEmitter) | |
{ | |
this.signalEmitter = signalEmitter; | |
} | |
} | |
void Awake(){ | |
_signalReceiver = gameObject.GetComponent<SignalReceiver>(); | |
foreach (var ot in director.playableAsset.outputs){ | |
switch (ot.outputTargetType.Name) | |
{ | |
case "SignalReceiver": | |
SignalTrack signalTrack = ot.sourceObject as SignalTrack; | |
IEnumerable<IMarker> markers = signalTrack.GetMarkers(); | |
if (markers != null) | |
{ | |
foreach (var marker in markers) | |
{ | |
SignalEmitter signalEmitter = marker as SignalEmitter; | |
if (signalEmitter != null) | |
{ | |
signalEmitters.Add(new SignalEmitterInfo(signalEmitter)); | |
} | |
} | |
} | |
break; | |
} | |
} | |
} | |
void FixedUpdate(){ | |
if (director.timeUpdateMode == DirectorUpdateMode.Manual) | |
{ | |
foreach (SignalEmitterInfo signalEmitterInfo in signalEmitters) | |
{ | |
SignalEmitter signalEmitter = signalEmitterInfo.signalEmitter; | |
if (signalEmitter.emitOnce && signalEmitterInfo.isInvoke) | |
{ | |
// 只能调用一次 且调用过 | |
}else | |
{ | |
// 可以调用多次 或 还没调用 | |
if (director.time >= signalEmitter.time) | |
{ | |
UnityEvent unityEvent = _signalReceiver.GetReaction(signalEmitter.asset); | |
unityEvent.Invoke(); | |
signalEmitterInfo.isInvoke = true; | |
} | |
} | |
} | |
if (!isStop) | |
{ | |
if (director.state == PlayState.Playing) | |
{ | |
if (director.time >= director.duration) | |
{ | |
HoldStop(); | |
} | |
else | |
{ | |
director.time += Time.deltaTime; | |
director.Evaluate(); | |
} | |
} | |
} | |
} | |
} |