// by chai using System; using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.Events; namespace TweenAnimation { // tween播放过程中产生事件 [Serializable] public class TweenEvent { public string name; // 事件名 public float time; // 事件触发时间 public UnityEvent eventHandler; // 回调函数 #if UNITY_EDITOR [NonSerialized] public bool unfold = false; #endif [NonSerialized] public bool trigged = false; public TweenEvent() { name = "New Event"; time = 0; eventHandler = null; } } public class TweenAnimation : MonoBehaviour { public enum EventTriggeredDirection { None = 0, Forward = 1, Backward = 2, } public enum PlaybackStyle { Once, Loop, PingPong, } public new string name = "New Animation"; [SerializeReference] public List modules; public float duration; public PlaybackStyle playbackStyle; public EventTriggeredDirection eventTriggeredDirection; // 回放次数,0是不限制,默认是0 public int playbackLimit; // 是否触发事件 public bool triggerEvents; // 只触发一次事件 public bool triggerOnce; // 脚本中处理 ITweenEventHandler public bool scriptHandler; public List eventList; // 默认的事件回调函数 public UnityEvent onStart; public UnityEvent onTurnStart; public UnityEvent onTurnEnd; public UnityEvent onEnd; // 上次更新时的时间(一个turn内的) private float m_LastPlaybackTurnTime; public TweenAnimation() { this.playbackStyle = PlaybackStyle.Loop; this.playbackLimit = 0; this.duration = 1; this.modules = new List(); this.triggerOnce = false; m_LastPlaybackTurnTime = -0.001f; } public void AddModule(TweenModule module) { if (modules == null) modules = new List(); modules.Add(module); } public void RemoveModule(TweenModule module) { if (modules == null) return; if (modules.Contains(module)) modules.Remove(module); } public void AddEvent(TweenEvent e) { if (eventList == null) eventList = new List(); eventList.Add(e); } public void RemoveEvent(TweenEvent e) { if (eventList == null) return; eventList.Remove(e); } public void BeforePlay() { m_LastPlaybackTurnTime = -0.001f; ResetEventTriggerFlag(); } private void ResetEventTriggerFlag() { for(int i = 0; i < eventList.Count; ++i) { var e = eventList[i]; if (e == null) continue; e.trigged = false; } } /// /// 根据时间执行tween, time是从播放开始的真实时间 /// /// real time public void Process(float time) { if (modules == null) return; float limitTime = ApplyLimit(time); // 转换为playback limit后的逻辑时间 float logicTime = HandleTime(limitTime); // 转换为1个turn内的逻辑时间 // 处理事件 if(triggerEvents) { if (limitTime >= 0 && m_LastPlaybackTurnTime < 0) onStart.Invoke(); bool isPingpong = playbackStyle == PlaybackStyle.PingPong; for (int i = 0; i < eventList.Count; ++i) { var e = eventList[i]; if (e == null) continue; if (triggerOnce && e.trigged) continue; float t = e.time; bool bTrigger = false; bool isOdd = (((int)(limitTime / duration)) & 1) == 1; if (isPingpong && isOdd && (eventTriggeredDirection & EventTriggeredDirection.Backward) == 0) continue; if (isPingpong && !isOdd && (eventTriggeredDirection & EventTriggeredDirection.Forward) == 0) continue; if (isPingpong && isOdd) bTrigger = logicTime <= t && m_LastPlaybackTurnTime > t; else bTrigger = logicTime >= t && m_LastPlaybackTurnTime < t; if(bTrigger && e.eventHandler != null) { e.eventHandler.Invoke(); if (triggerOnce) e.trigged = true; } } m_LastPlaybackTurnTime = logicTime; } // 更新动画 for (int i = 0; i < modules.Count; i ++) { TweenModule module = modules[i]; if (!module.enabled) continue; module.OnUpdate(logicTime); } } float HandleOnce(float time) { time = Mathf.Clamp(time, 0, duration); return time; } float HandleLoop(float time) { time = time % duration; return time; } float HandlePingpong(float time) { if (time <= duration) return time; float remain = time % duration; int round = (int)(time / duration); bool bOdd = (round & 1) == 1; if (bOdd) time = duration - remain; else time = remain; return time; } // 返回[0,duration]范围内的逻辑时间 public float HandleTime(float time) { float logicTime = time; if (this.playbackStyle == PlaybackStyle.Once) logicTime = HandleOnce(time); else if (this.playbackStyle == PlaybackStyle.Loop) logicTime = HandleLoop(time); else if (this.playbackStyle == PlaybackStyle.PingPong) logicTime = HandlePingpong(time); return logicTime; } // 返回真实时间对应的逻辑时间 public float ApplyLimit(float time) { if (playbackLimit <= 0) return time; if (playbackStyle == PlaybackStyle.Loop) time = Mathf.Clamp(time, 0, playbackLimit * duration - 0.001f); // 0.001是为了防止HandleTime的mod等于0 else if(playbackStyle == PlaybackStyle.PingPong) time = Mathf.Clamp(time, 0, playbackLimit * duration); return time; } #if UNITY_EDITOR public void UpdateEditor(float time) { Process(time); } // 返回0-duration内的时间,用负数代表从右往左 public float GetIdentifiedTime(float t) { int round = (int)(t / duration); float time = HandleTime(t); if(playbackStyle == PlaybackStyle.PingPong) { bool bOdd = (round & 1) == 1; if(bOdd) time = -time; } return time; } #endif } }