using UnityEngine; using System.Collections; using System.Collections.Generic; #if UNITY_EDITOR using System.IO; #endif public enum AnimatorEventType { Effect, CameraShake, Msg, } [System.Serializable] public class MsgEvent { public MsgEvent() { type = AnimatorEventType.Msg; } public string msgFunction; public string msgParams; public AnimatorEventType type; public string name = ""; public int layer = -1; public float normalizedTime = 0.0f; public bool IsEquals(object obj) { MsgEvent other = obj as MsgEvent; if (other == null) return false; if (this.layer != other.layer || this.type != other.type || this.name != other.name || Mathf.Abs(this.normalizedTime - other.normalizedTime) > Mathf.Epsilon|| this.msgFunction != other.msgFunction || this.msgParams != other.msgParams) return false; return true; } } [System.Serializable] public class EventDataDic { public int stateHash; public List eventList; public EventDataDic(int hash) { stateHash = hash; eventList=new List(); } } [System.Serializable] public class AnimatorEventDatas { public List m_animatorEventData = null; public void MakeSureEventList(int stateHash) { if (m_animatorEventData != null) { foreach (var eventList in m_animatorEventData) { if (eventList.stateHash == stateHash) return; } } else { m_animatorEventData = new List(); } m_animatorEventData.Add(new EventDataDic(stateHash)); } public List GetEventList(int stateHash) { if (m_animatorEventData != null) { foreach (var dataEventDic in m_animatorEventData) { if (dataEventDic.stateHash == stateHash) return dataEventDic.eventList; } } return null; } public List GetEventList(int stateHash, int layerIndex) { if (m_animatorEventData != null) { List events = new List(); foreach (var dataEventDic in m_animatorEventData) { if (dataEventDic.stateHash == stateHash) { for (int i = 0; i < dataEventDic.eventList.Count; ++i) { if (dataEventDic.eventList[i].layer == layerIndex || dataEventDic.eventList[i].layer == -1) { events.Add(dataEventDic.eventList[i]); } } return events; } } } return null; } /// 干掉相同的事件 public bool RemoveSameEvents() { bool ret = false; foreach (var itemData in m_animatorEventData) { var elem = itemData.eventList; for (int i = elem.Count - 1; i >= 0; --i) { for (int j = i - 1; j >= 0; --j) { if (elem[i].IsEquals(elem[j])) { ret = true; Debug.Log("removesameevents: key=" + itemData.stateHash + " type=" + elem[i].type + " name=" + elem[i].name + " time=" + elem[i].normalizedTime + " layer=" + elem[i].layer); elem.RemoveAt(i); break; } } } } return ret; } public void Remove(int stateHash) { if (m_animatorEventData != null) { List deletEvents = new List(); foreach (var dataEventDic in m_animatorEventData) { if (dataEventDic.stateHash == stateHash) { deletEvents.Add(dataEventDic); } } foreach(var delDataEvent in deletEvents) { m_animatorEventData.Remove(delDataEvent); } } } public bool HasEventStateHash(int stateHash) { foreach (var dataEventDic in m_animatorEventData) { if( dataEventDic.stateHash== stateHash) { return true; } } return false; } public bool AddEvent(int stateHash, MsgEvent addEvent) { List eventList= GetEventList(stateHash); if (eventList==null) { eventList = new List(); var eventDataDic= new EventDataDic(stateHash); eventDataDic.eventList.Add(addEvent); m_animatorEventData.Add(eventDataDic); } else { eventList.Add(addEvent); } return true; } public bool RemoveEvent(int stateHash, MsgEvent deleteEvent) { List eventList = GetEventList(stateHash); if (eventList == null) { return false; } else { return eventList.Remove(deleteEvent); } } } [ExecuteInEditMode] [RequireComponent(typeof(Animator))] public class AnimatorEventHandler : MonoBehaviour { class LayerRuntime { public int stateNameHash = 0; public float stateNormalizedTime = -0.000001f; public float stateLength = 1; public bool stateLoop = false; } #region private members private Animator m_animator = null; public AnimatorEventDatas animatorEventData = null; private Dictionary m_layerRuntimeDictionary = new Dictionary(); #endregion #region public members public bool isUpdateEventInStateEndFrame = false; #endregion #region public properties public Animator animator { get { if (m_animator == null) { m_animator = GetComponent(); } return m_animator; } } #endregion void Start() { Init(); } void Init() { if (animatorEventData == null) { animatorEventData = new AnimatorEventDatas(); } m_layerRuntimeDictionary.Clear(); for (int i = 0; i < animator.layerCount; i++) { m_layerRuntimeDictionary.Add(i, new LayerRuntime()); } } public AnimatorStateInfo GetCurrentStateInfo(int layerIndex) { if (animator.IsInTransition(layerIndex)) { return animator.GetNextAnimatorStateInfo(layerIndex); } return animator.GetCurrentAnimatorStateInfo(layerIndex); } void Update() { if (animator == null) return; if (animatorEventData == null) return; if (Time.deltaTime <= 0) return; if(Application.isPlaying) { for (int i = 0; i < animator.layerCount; ++i) { _UpdateLayer(i); } } } void _UpdateLayerChild(float stateNormalizedTime, LayerRuntime layerRuntime, int layerIndex) { int stateNameHash = layerRuntime.stateNameHash; List eventList = animatorEventData.GetEventList(stateNameHash); if (eventList == null) return; float currentTime = Time.time; float currentNormalizedTime = stateNormalizedTime; float lastNormalizedTime = layerRuntime.stateNormalizedTime; layerRuntime.stateNormalizedTime = currentNormalizedTime; int currentTimeFloor = Mathf.FloorToInt(currentNormalizedTime); int lastTimeFloor = Mathf.FloorToInt(lastNormalizedTime); float stateLength = layerRuntime.stateLength; bool stateLoop = layerRuntime.stateLoop; for (int i = 0; i < eventList.Count; ++i) { MsgEvent animatorEvent = eventList[i]; if (layerIndex != animatorEvent.layer && animatorEvent.layer != -1) continue; if (!stateLoop) { float eventNormailzedTime = animatorEvent.normalizedTime; if (eventNormailzedTime > lastNormalizedTime && eventNormailzedTime <= currentNormalizedTime) { float deltaNormalizedTime = currentNormalizedTime - animatorEvent.normalizedTime; float eventFiredTime = currentTime - deltaNormalizedTime * stateLength; App.LuaMgr.CallFunction(eventList[i].msgFunction,eventList[i].msgParams); } } else { float floorTime = currentTime - Mathf.Repeat(currentNormalizedTime, 1f) * stateLength; for (int floor = currentTimeFloor; floor >= lastTimeFloor && floor >= 0; --floor, floorTime -= stateLength) { float eventNormailzedTime = floor + animatorEvent.normalizedTime; if (eventNormailzedTime > lastNormalizedTime && eventNormailzedTime <= currentNormalizedTime) { float eventFiredTime = floorTime + animatorEvent.normalizedTime * stateLength; App.LuaMgr.CallFunction(eventList[i].msgFunction, eventList[i].msgParams); } } } } } // 是否处理状态切换结束帧的事件 public bool IsUpdateEventInStateEndFrame { get { return isUpdateEventInStateEndFrame; } set { isUpdateEventInStateEndFrame = value; } } private LayerRuntime layerRuntime; void _UpdateLayer(int layerIndex) { AnimatorStateInfo stateInfo = GetCurrentStateInfo(layerIndex); if (stateInfo.length <= 0f) { // 对于Empty做处理(其实是异常情况) if (m_layerRuntimeDictionary.TryGetValue(layerIndex, out layerRuntime)) { layerRuntime.stateNameHash = stateInfo.fullPathHash; } return; } float _stateNormalizedTime = stateInfo.normalizedTime; if (!m_layerRuntimeDictionary.TryGetValue(layerIndex, out layerRuntime)) { return; } if (layerRuntime.stateNameHash != stateInfo.fullPathHash||(_stateNormalizedTime < 1&& (_stateNormalizedTime < layerRuntime.stateNormalizedTime|| Time.deltaTime > stateInfo.length))) { if (isUpdateEventInStateEndFrame && layerRuntime.stateNameHash != stateInfo.fullPathHash) { float stateNormalizedTime = layerRuntime.stateNormalizedTime+ (Time.deltaTime - _stateNormalizedTime * stateInfo.length) / layerRuntime.stateLength; if (stateNormalizedTime > 1) { stateNormalizedTime = 1; } _UpdateLayerChild(stateNormalizedTime, layerRuntime, layerIndex); } layerRuntime.stateLength = stateInfo.length; layerRuntime.stateLoop = stateInfo.loop; layerRuntime.stateNameHash = stateInfo.fullPathHash; layerRuntime.stateNormalizedTime = -1f; } _UpdateLayerChild(_stateNormalizedTime, layerRuntime, layerIndex); } IEnumerator UpdateLayer() { while (true) { yield return new WaitForEndOfFrame(); for (int i = 0; i < animator.layerCount; ++i) { _UpdateLayer(i); } } } }