2023-04-03 11:04:31 +08:00

256 lines
7.2 KiB
C#

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<string, PlayableBinding> tracks;
private Dictionary<GameObject, List<Component>> componentCache;
private List<FrameData> frameDatas;
public Action onComplete;
public TimeLineItem()
{
}
public double Duration {
get { return director.duration; }
}
public TimeLineItem(PlayableDirector pd)
{
director = pd;
frameDatas = new List<FrameData>();
tracks = new Dictionary<string, PlayableBinding>();
componentCache = new Dictionary<GameObject, List<Component>>();
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<Animator>())
{
List<Component> components;
if (componentCache.TryGetValue(gameObject, out components))
{
components.Add(gameObject.AddComponent<Animator>());
}
else
{
componentCache.Add(gameObject, new List<Component>() { gameObject.AddComponent<Animator>() });
}
}
}
}
}
private void CheckRemoveCacheComponents(UnityEngine.Object obj)
{
if (null != obj && obj is GameObject)
{
var gameObject = obj as GameObject;
List<Component> 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();
}
}
}