个人使用的事件管理者,用于项目中的事件分发,以增加代码的灵活性。
事件
由于本人习惯,本着“多一事不如少一事“”的原则,使用的是程序库中自带的事件EventHandler:
using System.Runtime.InteropServices;
namespace System
{
[ComVisible(true)]
public delegate void EventHandler(object sender, EventArgs e);
}
其中,参数EventArgs类,也是程序库中自带的:
using System.Runtime.InteropServices;
namespace System
{
[ComVisible(true)]
public class EventArgs
{
public static readonly EventArgs Empty;
public EventArgs();
}
}
管理者
using System;
using System.Collections.Generic;
using UnityEngine;
/// <summary>
/// 事件管理者
/// </summary>
public class EventManager : Singleton<EventManager>
{
Dictionary<GameObject, Dictionary<Type, EventHandler>> m_dic = new Dictionary<GameObject, Dictionary<Type, EventHandler>>();
/// <summary>
/// 增加事件
/// </summary>
/// <typeparam name="T">事件的参数类</typeparam>
/// <param name="owner">拥有对象</param>
/// <param name="eh">事件</param>
public void AddEvent<T>(GameObject owner, EventHandler eh) where T : EventArgs
{
if (!m_dic.ContainsKey(owner))
{
m_dic[owner] = new Dictionary<Type, EventHandler>();
}
Type type = typeof(T);
if (m_dic[owner].ContainsKey(type))
{
m_dic[owner][type] += eh;
}
else
{
m_dic[owner][type] = eh;
}
}
/// <summary>
/// 触发事件
/// </summary>
/// <typeparam name="T">事件的参数类</typeparam>
/// <param name="owner">拥有对象</param>
/// <param name="sender">事件的参数</param>
/// <param name="t">事件的参数</param>
public void TriggerEvent<T>(GameObject owner, object sender, T t) where T : EventArgs
{
if (m_dic.ContainsKey(owner))
{
Type type = typeof(T);
if (m_dic[owner].ContainsKey(type))
{
m_dic[owner][type].Invoke(sender, t);
}
}
}
/// <summary>
/// 移除事件
/// </summary>
/// <typeparam name="T">事件的参数类</typeparam>
/// <param name="owner">拥有对象</param>
/// <param name="eh">事件</param>
public void RemoveEvent<T>(GameObject owner, EventHandler eh) where T : EventArgs
{
if (m_dic.ContainsKey(owner))
{
Type type = typeof(T);
if (m_dic[owner].ContainsKey(type))
{
m_dic[owner][type] -= eh;
}
}
}
}
该类为单例,继承的便是我自己编写的一个单例父类,之前有篇专门记录的文章:可点击查看相关文章。
在代码中,有一个两重字典,用于准确确定到我们所要用到的事件。第一重为GameObject类型,是场景中的一个物体;第二重为一个衍生自EventArgs类型的类的类型。
使用
使用这个事件管理者时,先写一个与事件EventHandler结构一样的一个函数:
public void TestEvent(object sender, EventArgs e)
{
}
然后再创建一个衍生自EventArgs类型的类:
public class TestEventArgs : EventArgs
{
}
然后将函数中所要真正用到的参数,以字段的形式创建于该类中。再只需要在函数中,将EventArgs类的参数转换成对应类型(如例:TestEventArgs)
public void TestEvent(object sender, EventArgs e)
{
TestEventArgs tea=(TestEventArgs)e;
}
便可以获取到真正传入的所需要的参数了。在其之后便可编写执行逻辑。
使用事件前先将其添加入事件管理者:
EventManager.GetInstance().AddEvent<TestEventArgs>(gameObject, TestEvent);
触发事件时:
EventManager.GetInstance().TriggerEvent(gameObject, 0, new TestEventArgs());
其中的数字0,便是函数的第1个object类型的参数,如有需要,可自行更改。
最后不需要其事件时,可以将其在管理者中删除:
EventManager.GetInstance().RemoveEvent<TestEventArgs>(gameObject, TestEvent);
简化扩展
UnityAction
Unity中给出了一个UnityEngine.Events
命名空间,里面有2个已经定义好的事件:
一个是无参的事件;
namespace UnityEngine.Events
{
//
// 摘要:
// Zero argument delegate used by UnityEvents.
public delegate void UnityAction();
}
另一个是有一个参数的事件。
namespace UnityEngine.Events
{
public delegate void UnityAction<T0>(T0 arg0);
}
UnityEvent
然后,还有两个根据上面两种事件封装好的事件类,分别是:
namespace UnityEngine.Events
{
//
// 摘要:
// A zero argument persistent callback that can be saved with the Scene.
public class UnityEvent : UnityEventBase
{
//
// 摘要:
// Constructor.
[RequiredByNativeCode]
public UnityEvent();
//
// 摘要:
// Add a non persistent listener to the UnityEvent.
//
// 参数:
// call:
// Callback function.
public void AddListener(UnityAction call);
//
// 摘要:
// Invoke all registered callbacks (runtime and persistent).
public void Invoke();
//
// 摘要:
// Remove a non persistent listener from the UnityEvent.
//
// 参数:
// call:
// Callback function.
public void RemoveListener(UnityAction call);
protected override MethodInfo FindMethod_Impl(string name, object targetObj);
}
}
namespace UnityEngine.Events
{
//
// 摘要:
// One argument version of UnityEvent.
public abstract class UnityEvent<T0> : UnityEventBase
{
[RequiredByNativeCode]
public UnityEvent();
public void AddListener(UnityAction<T0> call);
public void Invoke(T0 arg0);
public void RemoveListener(UnityAction<T0> call);
protected override MethodInfo FindMethod_Impl(string name, object targetObj);
}
}
UnityEventManager
结合上面的事件管理者,便归纳总结了下面的脚本:
using System;
using System.Collections.Generic;
using UnityEngine.Events;
public class UnityEventManager : Singleton<UnityEventManager>
{
private UnityEventManager()
{
m_UnityEventDic = new Dictionary<Type, UnityEventArgs>();
}
private Dictionary<Type, UnityEventArgs> m_UnityEventDic;
/// <summary>
/// 增加事件
/// </summary>
/// <typeparam name="T">事件的参数类</typeparam>
/// <param name="uEvent">事件</param>
public void AddEvent<T>(UnityAction<EventArgs> uEvent) where T : EventArgs
{
Type type = typeof(T);
if (m_UnityEventDic.ContainsKey(type))
{
m_UnityEventDic[type].AddListener(uEvent);
}
else
{
m_UnityEventDic[type] = new UnityEventArgs();
m_UnityEventDic[type].AddListener(uEvent);
}
}
/// <summary>
/// 触发事件
/// </summary>
/// <typeparam name="T">事件的参数类</typeparam>
/// <param name="t">事件的参数</param>
public void TriggerEvent<T>(T t) where T : EventArgs
{
Type type = typeof(T);
if (m_UnityEventDic.ContainsKey(type))
{
m_UnityEventDic[type].Invoke(t);
}
}
/// <summary>
/// 移除事件
/// </summary>
/// <typeparam name="T">事件的参数类</typeparam>
/// <param name="uEvent">事件</param>
public void RemoveEvent<T>(UnityAction<EventArgs> uEvent) where T : EventArgs
{
Type type = typeof(T);
if (m_UnityEventDic.ContainsKey(type))
{
m_UnityEventDic[type].RemoveListener(uEvent);
}
}
private class UnityEventArgs : UnityEvent<EventArgs>
{
}
}