using System; using System.Collections; using Cinemachine; using UnityEngine; using UnityEngine.Playables; using UnityEngine.ResourceManagement.AsyncOperations; using UnityEngine.Timeline; using AibisDream.Framework; namespace AibisDream { public class DirectorHandler : MonoBehaviour { private const string TimelinePrefix = "Timeline/"; public string timelineName; [SerializeField] private PlayableDirector director; [Header("Cinemachine 自动绑定")] [Tooltip("加载新 Timeline 时自动绑定 CinemachineBrain")] [SerializeField] private bool autoBindCinemachineBrain; private Action _onCompleteCallback; private AsyncOperationHandle _addressableHandle; private PlayableAsset _savedPlayableAsset; #if UNITY_EDITOR /// /// 在 Editor 中,当组件创建或 Inspector 变化时自动查找同物体上的 PlayableDirector /// private void OnValidate() { if (director == null) { director = GetComponent(); } } #endif private void Awake() { if (director == null) { director = GetComponent(); } } private void Start() { TimelineCenter.Instance.RegisterDirector(this); } private void OnDestroy() { TimelineCenter.Instance.UnregisterDirector(this); if (director != null) { director.stopped -= OnDirectorStopped; } ReleaseAddressableHandle(); } private void ReleaseAddressableHandle() { if (!_addressableHandle.IsValid()) return; if (director != null && director.playableAsset == _addressableHandle.Result) { director.playableAsset = _savedPlayableAsset; } ResourceKit.Release(_addressableHandle); _addressableHandle = default; } /// /// 自动绑定 CinemachineBrain 到 Timeline 中的所有 CinemachineTrack /// private void AutoBindCinemachineBrain() { Debug.Log($"[DirectorHandler] {timelineName}: AutoBindCinemachineBrain 被调用,autoBindCinemachineBrain={autoBindCinemachineBrain}"); if (!autoBindCinemachineBrain) { Debug.Log($"[DirectorHandler] {timelineName}: autoBindCinemachineBrain 为 false,跳过绑定"); return; } if (director == null) { Debug.LogError($"[DirectorHandler] {timelineName}: director 为 null"); return; } if (director.playableAsset == null) { Debug.LogError($"[DirectorHandler] {timelineName}: director.playableAsset 为 null"); return; } // 获取目标 CinemachineBrain var mainCamera = Camera.main; if (mainCamera == null) { Debug.LogError($"[DirectorHandler] {timelineName}: Camera.main 为 null"); return; } var brain = mainCamera.GetComponent(); if (brain == null) { Debug.LogWarning($"[DirectorHandler] {timelineName}: 主摄像机上找不到 CinemachineBrain,无法自动绑定"); return; } Debug.Log($"[DirectorHandler] {timelineName}: 找到 CinemachineBrain,准备绑定"); // 遍历所有输出轨道,找到 CinemachineTrack 并绑定 var timelineAsset = director.playableAsset as TimelineAsset; if (timelineAsset == null) { Debug.LogError($"[DirectorHandler] {timelineName}: playableAsset 不是 TimelineAsset"); return; } int trackCount = 0; int boundCount = 0; foreach (var track in timelineAsset.GetOutputTracks()) { trackCount++; Debug.Log($"[DirectorHandler] {timelineName}: 检查轨道 {track.name},类型: {track.GetType().Name}"); // 直接检查轨道类型 if (track is CinemachineTrack) { director.SetGenericBinding(track, brain); boundCount++; Debug.Log($"[DirectorHandler] {timelineName}: 成功绑定轨道 {track.name}"); } } Debug.Log($"[DirectorHandler] {timelineName}: 共检查 {trackCount} 个轨道,绑定了 {boundCount} 个 CinemachineTrack"); } /// /// 播放 Timeline /// public void Play(Action onComplete = null) { if (director == null) { Debug.LogError($"DirectorHandler {timelineName}: PlayableDirector is null"); return; } // 先停止再播放 director.stopped -= OnDirectorStopped; if (director.state == PlayState.Playing) { director.Stop(); } _onCompleteCallback = onComplete; // 如果有完成回调,订阅 stopped 事件 if (onComplete != null) { director.stopped += OnDirectorStopped; } // 自动绑定 CinemachineBrain AutoBindCinemachineBrain(); director.Play(); } /// /// 异步播放 Timeline(协程版本) /// public IEnumerator PlayAsync() { if (director == null) { Debug.LogError($"DirectorHandler {timelineName}: PlayableDirector is null"); yield break; } // 先停止再播放 if (director.state == PlayState.Playing) { director.Stop(); } // 自动绑定 CinemachineBrain AutoBindCinemachineBrain(); director.Play(); // 等待播放完成 while (director.state == PlayState.Playing) { yield return null; } } /// /// 从 Addressables 加载 PlayableAsset 并播放(加载时自动加 "Timeline/" 前缀) /// public void PlayFromAddressable(string addressableKey, Action onComplete = null) { StartCoroutine(PlayFromAddressableCoroutine(addressableKey, onComplete)); } /// /// 从 Addressables 加载 PlayableAsset 并播放(协程版本,可等待播完) /// public IEnumerator PlayFromAddressableAsync(string addressableKey) { yield return PlayFromAddressableCoroutine(addressableKey, null); } private IEnumerator PlayFromAddressableCoroutine(string addressableKey, Action onComplete) { if (director == null) { Debug.LogError($"DirectorHandler {timelineName}: PlayableDirector is null"); yield break; } if (string.IsNullOrEmpty(addressableKey)) { Debug.LogError($"DirectorHandler {timelineName}: addressableKey is null or empty"); yield break; } // 播放新 Addressable 前,先释放上一次 ReleaseAddressableHandle(); var loadKey = TimelinePrefix + addressableKey; PlayableAsset loadedAsset = null; AsyncOperationHandle loadedHandle = default; var loadDone = false; ResourceKit.LoadAssetAsyncWithHandle(loadKey, handle => { loadedHandle = handle; if (handle.Status == AsyncOperationStatus.Succeeded) loadedAsset = handle.Result; loadDone = true; }); yield return new WaitUntil(() => loadDone); if (loadedAsset == null) { Debug.LogError($"DirectorHandler {timelineName}: Failed to load PlayableAsset '{loadKey}'"); yield break; } director.stopped -= OnDirectorStopped; if (director.state == PlayState.Playing) { director.Stop(); } _savedPlayableAsset = director.playableAsset; director.playableAsset = loadedAsset; director.RebuildGraph(); // 自动绑定 CinemachineBrain(必须在 RebuildGraph 之后) AutoBindCinemachineBrain(); _addressableHandle = loadedHandle; _onCompleteCallback = onComplete; if (onComplete != null) { director.stopped += OnDirectorStopped; } director.Play(); // 等待播放完成(与 PlayAsync 行为一致) while (director.state == PlayState.Playing) { yield return null; } } /// /// 停止播放 /// public void Stop() { if (director == null) return; // 先取消事件订阅,避免 Stop() 触发回调 director.stopped -= OnDirectorStopped; director.Stop(); _onCompleteCallback = null; ReleaseAddressableHandle(); } /// /// 暂停播放 /// public void Pause() { if (director == null) return; if (director.state == PlayState.Playing) { director.Pause(); } } /// /// 恢复播放 /// public void Resume() { if (director == null) return; if (director.state == PlayState.Paused) { director.Resume(); } } /// /// 重置 Timeline /// public void Reset() { if (director == null) return; // 先取消事件订阅,避免 Stop() 触发回调 director.stopped -= OnDirectorStopped; director.Stop(); director.time = 0; director.Evaluate(); _onCompleteCallback = null; ReleaseAddressableHandle(); } /// /// 获取当前播放时间 /// public double GetPlaybackTime() { if (director == null) return 0; return director.time; } /// /// 获取总时长 /// public double GetDuration() { if (director == null) return 0; return director.duration; } /// /// 设置播放速度 /// public void SetPlaybackSpeed(float speed) { if (director == null) return; if (director.playableGraph.IsValid()) { director.playableGraph.GetRootPlayable(0).SetSpeed(speed); } else { Debug.LogWarning($"DirectorHandler {timelineName}: PlayableGraph is not valid. Cannot set playback speed."); } } /// /// 跳转到指定时间点 /// public void SeekToTime(double time) { if (director == null) return; director.time = Math.Clamp(time, 0, director.duration); director.Evaluate(); } /// /// Director 停止事件处理 /// private void OnDirectorStopped(PlayableDirector director) { // 立即取消订阅,避免重复触发 director.stopped -= OnDirectorStopped; var callback = _onCompleteCallback; _onCompleteCallback = null; ReleaseAddressableHandle(); callback?.Invoke(); } } }