384 lines
10 KiB
C#
384 lines
10 KiB
C#
|
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<MsgEvent> eventList;
|
|||
|
|
|||
|
public EventDataDic(int hash)
|
|||
|
{
|
|||
|
stateHash = hash;
|
|||
|
eventList=new List<MsgEvent>();
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
[System.Serializable]
|
|||
|
public class AnimatorEventDatas
|
|||
|
{
|
|||
|
public List<EventDataDic> 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<EventDataDic>();
|
|||
|
}
|
|||
|
m_animatorEventData.Add(new EventDataDic(stateHash));
|
|||
|
}
|
|||
|
|
|||
|
public List<MsgEvent> GetEventList(int stateHash)
|
|||
|
{
|
|||
|
if (m_animatorEventData != null)
|
|||
|
{
|
|||
|
foreach (var dataEventDic in m_animatorEventData)
|
|||
|
{
|
|||
|
if (dataEventDic.stateHash == stateHash)
|
|||
|
return dataEventDic.eventList;
|
|||
|
}
|
|||
|
}
|
|||
|
return null;
|
|||
|
}
|
|||
|
|
|||
|
public List<MsgEvent> GetEventList(int stateHash, int layerIndex)
|
|||
|
{
|
|||
|
if (m_animatorEventData != null)
|
|||
|
{
|
|||
|
List<MsgEvent> events = new List<MsgEvent>();
|
|||
|
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<EventDataDic> deletEvents = new List<EventDataDic>();
|
|||
|
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<MsgEvent> eventList= GetEventList(stateHash);
|
|||
|
if (eventList==null)
|
|||
|
{
|
|||
|
eventList = new List<MsgEvent>();
|
|||
|
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<MsgEvent> 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<int, LayerRuntime> m_layerRuntimeDictionary = new Dictionary<int, LayerRuntime>();
|
|||
|
#endregion
|
|||
|
|
|||
|
#region public members
|
|||
|
public bool isUpdateEventInStateEndFrame = false;
|
|||
|
#endregion
|
|||
|
|
|||
|
#region public properties
|
|||
|
public Animator animator {
|
|||
|
get {
|
|||
|
if (m_animator == null) {
|
|||
|
m_animator = GetComponent<Animator>();
|
|||
|
}
|
|||
|
|
|||
|
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<MsgEvent> 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);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|