# 背景

根据策划需求要在剧情中加入战斗,战斗结束后继续播放剧情。我添加了自定义 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();
                }
            }
        }
    }
}
更新于 阅读次数