using System; using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.Playables; using Object = UnityEngine.Object; namespace BF { public class TimeLineItem { public struct FrameData { public double time; public System.Action e; public FrameData(double t, System.Action a) { time = t; e = a; } } private bool play; private double time; private PlayableDirector director; private Dictionary tracks; private Dictionary> componentCache; private List frameDatas; public Action onComplete; public TimeLineItem() { } public double Duration { get { return director.duration; } } public TimeLineItem(PlayableDirector pd) { director = pd; frameDatas = new List(); tracks = new Dictionary(); componentCache = new Dictionary>(); GetTracks(); } private void GetTracks() { if (null == director.playableAsset || null == director.playableAsset.outputs) return; foreach (var at in director.playableAsset.outputs) { if (!tracks.ContainsKey(at.streamName)) { tracks.Add(at.streamName, at); } } } private void CheckBindingType(UnityEngine.Object bindingObj, UnityEngine.Object obj) { if (bindingObj.GetType() == typeof(UnityEngine.Timeline.AnimationTrack)) { if (obj is GameObject) { var gameObject = obj as GameObject; if (!gameObject.HasComponent()) { List components; if (componentCache.TryGetValue(gameObject, out components)) { components.Add(gameObject.AddComponent()); } else { componentCache.Add(gameObject, new List() { gameObject.AddComponent() }); } } } } } private void CheckRemoveCacheComponents(UnityEngine.Object obj) { if (null != obj && obj is GameObject) { var gameObject = obj as GameObject; List components; if (componentCache.TryGetValue(gameObject, out components)) { foreach (var component in components) { Object.Destroy(component); } } componentCache.Remove(gameObject); } } public void FrameMove(double delta) { if (play && time > 0) { time -= delta; ExecuteEvent(Duration - time); if (time <= 0) { if (null != onComplete) onComplete(); } } } public void RegisterEvent(double time, Action e) { frameDatas.TryAdd(new FrameData(time, e)); frameDatas.Sort(FrameSort); } private int FrameSort(FrameData a, FrameData b) { return a.time <= b.time ? -1 : 1; } private void ClearEvent() { frameDatas.Clear(); } private void ExecuteEvent(double time) { for (int i = 0; i < frameDatas.Count; i++) { if (time >= frameDatas[i].time) { var e = frameDatas[i].e; if (null != e) e(); frameDatas.RemoveAt(i); } } } public void Play() { play = true; time = Duration; director.Play(); } public void Pause() { play = false; director.Pause(); } public void Resume() { play = true; director.Resume(); } public void Stop() { play = false; director.Stop(); } public void Reset(double timePoint) { timePoint = timePoint >= 0 ? timePoint : 0; timePoint = timePoint <= Duration ? timePoint : Duration; director.time = timePoint; play = false; time = Duration - timePoint; } public void ResetAndPlay(double timePoint) { timePoint = timePoint >= 0 ? timePoint : 0; timePoint = timePoint <= Duration ? timePoint : Duration; director.time = timePoint; play = true; time = Duration - timePoint; director.Play(); } public void Reset() { director.time = 0; play = false; time = Duration; } public void ResetAndPlay() { director.time = 0; play = true; time = Duration; director.Play(); } public UnityEngine.Object GetBindingObject(string trackName) { PlayableBinding playableBinding; if (tracks.TryGetValue(trackName, out playableBinding)) { return director.GetGenericBinding(playableBinding.sourceObject); } return null; } public void Binding(string trackName, UnityEngine.Object obj) { PlayableBinding playableBinding; if (tracks.TryGetValue(trackName, out playableBinding)) { CheckRemoveCacheComponents(director.GetGenericBinding(playableBinding.sourceObject)); CheckBindingType(playableBinding.sourceObject, obj); director.SetGenericBinding(playableBinding.sourceObject, obj); } } public void UnBinding(string trackName) { PlayableBinding playableBinding; if (tracks.TryGetValue(trackName, out playableBinding)) { CheckRemoveCacheComponents(director.GetGenericBinding(playableBinding.sourceObject)); director.SetGenericBinding(playableBinding.sourceObject, null); } } public void ClearAllBinding() { foreach (var track in tracks) { CheckRemoveCacheComponents(director.GetGenericBinding(track.Value.sourceObject)); director.ClearGenericBinding(track.Value.sourceObject); } } public void Clear() { ClearAllBinding(); tracks.Clear(); ClearEvent(); } } }