using System;
using System.Text;
using UnityEngine;
//using LuaInterface;
//using UnityEngine.Events;
using System.Collections.Generic;
namespace LuaFramework
{
[RequireComponent(typeof(Animator))]
public class AnimEventListener : MonoBehaviour
{
public readonly object EMPTY_ARG = new object();
private Animator animator;
private Dictionary<string, AnimEvent> eventsMap;
private StringBuilder strBuilder;
public delegate void ObjectDelegate(object arg0);
public delegate void VoidDelegate();
public static AnimEventListener Get(GameObject go)
{
if (go == null)
return null;
AnimEventListener listener = go.GetComponent<AnimEventListener>();
if (listener == null)
listener = go.AddComponent<AnimEventListener>();
return listener;
}
void Awake()
{
animator = GetComponent<Animator>();
strBuilder = new StringBuilder ();
eventsMap = new Dictionary<string, AnimEvent>();
}
//该gameObject上的animator组件的所有animation事件统一回调到这
public void OnAnimEvent(AnimationEvent animEvent)
{
if (animEvent == null) return;
AnimEvent eventParam = null;
if (eventsMap.TryGetValue(animEvent.stringParameter, out eventParam))
{
eventParam.Invoke();
}
}
private bool _AddEvent(string animName, string animEventName, float time, AnimEvent eventParam)
{
//接下来通过animName找到对应的animation clip
AnimationClip[] clips = animator.runtimeAnimatorController.animationClips;
AnimationClip target = null;
for (int i = 0; i < clips.Length; i++)
{
if (animName == clips[i].name)
{
target = clips[i];
break;
}
}
if (target == null)
{
Debug.LogWarningFormat
("not found animation clip #{0}# on GameObject #{1}#", animName, gameObject.name);
return false;
}
//创建一个AnimationEvent:
//此gameObject所有的animation事件统一回调到OnAnimEvent()函数上
AnimationEvent animEvent = new AnimationEvent();
animEvent.time = time;
animEvent.functionName = "OnAnimEvent";
animEvent.stringParameter = animEventName;
eventsMap[animEventName] = eventParam;
target.AddEvent(animEvent);
return true;
}
/// <summary>
/// 监听无参回调函数事件
/// </summary>
// Tolua Wrap带委托参数类型的函数不支持重载,暂时用后缀区分,可用LuaFunction代替
public bool AddEvent1(string animName, float time, VoidDelegate callback)
{
string animEventName = GetAnimEventName (animName, time);
//如果animEventName没被监听过
AnimEvent eventParam = null;
if (!eventsMap.TryGetValue(animEventName, out eventParam))
{
eventParam = new AnimEvent(callback);
eventParam.animName = animName;
eventParam.animEventname = animEventName;
return _AddEvent (animName, animEventName, time, eventParam);
}
else
{
eventParam.AddListener(callback);
}
return true;
}
/// <summary>
/// 监听有参回调函数事件
/// <animName> 动画名称
/// <time> 动画事件出发时刻(time <= animName总长度)
/// <callback> 动画事件回调函数
/// <arg0> 动画事件回调函数参数
/// </summary>
// Tolua Wrap带委托参数类型的函数不支持重载,暂时用后缀区分,可用LuaFunction代替
public bool AddEvent2(string animName, float time, ObjectDelegate callback, object arg0)
{
string animEventName = GetAnimEventName (animName, time, arg0);
if (string.IsNullOrEmpty (animEventName))
return false;
//如果animEventName没被监听过
AnimEvent eventParam = null;
if (!eventsMap.TryGetValue(animEventName, out eventParam))
{
eventParam = new AnimEvent(arg0, callback);
eventParam.animName = animName;
eventParam.animEventname = animEventName;
return _AddEvent (animName, animEventName, time, eventParam);
}
else
{
eventParam.AddListener(callback);
}
return true;
}
//移除name为animaName的animation clip所有监听
public void RemoveEvent(string animName)
{
List<string> events = new List<string> ();
foreach (var item in eventsMap)
{
if (item.Value.animName.Equals(animName))
{
item.Value.RemoveAllListeners ();
events.Add (item.Key);
}
}
foreach (var item in events)
{
eventsMap.Remove (item);
}
}
//移除name为animaName的animation clip在time时刻所有的监听
public void RemoveEvent(string animName, float time)
{
string pattern = string.Format ("{0}_{1}", animName, time);
List<string> events = new List<string> ();
foreach (var item in eventsMap)
{
AnimEvent ae = item.Value;
if (item.Key.StartsWith(pattern) && !ae.animName.Equals(pattern))
{
ae.RemoveAllListeners ();
events.Add (item.Key);
}
}
foreach (var item in events)
{
eventsMap.Remove (item);
}
}
//获取animation event name
private string GetAnimEventName(string animName, float time, object arg0 = null)
{
//StringBuild:效率高,线程非安全。多线程可以用StringBuffer
//animation name,trigger time,arg0的HashCode拼接作为事件的唯一标识符
strBuilder.Remove (0, strBuilder.Length);
strBuilder.AppendFormat ("{0}_{1}", animName, time);
strBuilder.Append ('_');
if (arg0 == null)
{
strBuilder.Append (EMPTY_ARG.GetHashCode ());
} else
{
strBuilder.Append (arg0.GetHashCode ());
}
return strBuilder.ToString ();
}
private void ClearEventsMap()
{
if (eventsMap == null)
return;
foreach (var item in eventsMap)
{
item.Value.RemoveAllListeners ();
}
}
void OnDestroy()
{
ClearEventsMap ();
}
public void Print(){
foreach (var item in eventsMap) {
Debug.LogFormat ("eventName:{0}", item.Key);
}
}
public class AnimEvent
{
private object arg0;
private event ObjectDelegate m_objectEvent;
private event VoidDelegate m_voidEvent;
public string animName;
public string animEventname;
public AnimEvent(object arg0, ObjectDelegate callback)
{
this.arg0 = arg0;
m_objectEvent += callback;
m_voidEvent = null;
}
public AnimEvent(VoidDelegate callback)
{
arg0 = null;
m_objectEvent = null;
m_voidEvent += callback;
}
public void Invoke()
{
if (m_objectEvent != null)
{
m_objectEvent (arg0);
}
else if (m_voidEvent != null)
{
m_voidEvent ();
}
}
public void AddListener(VoidDelegate callback)
{
m_voidEvent += callback;
}
public void RemoveListener(VoidDelegate callback)
{
m_voidEvent -= callback;
}
public void AddListener(ObjectDelegate callback)
{
m_objectEvent += callback;
}
public void RemoveListener(ObjectDelegate callback)
{
m_objectEvent -= callback;
}
public void RemoveAllListeners()
{
m_objectEvent = null;
m_voidEvent = null;
}
}
}
}
使用实例:
1 local UE = UnityEngine
2 local GO = UE.GameObject
3 local LF = LuaFramework
4 local AEL = LF.AnimEventListener
7
8 function Main()
9 player = GO.Find("Player")
10 --在player的"run"动画播放1s时添加一个事件
11 AEL.Get(player):AddEvent1("Run", 1, OnRunOneSecond)
12 animator = player:GetComponent(typeof(UE.Animator)) end
15
30 function OnRunOneSecond()
31 print("OnRunOneSecond")
32 end