目录
前言
事件中心的结构
EventManager事件管理器
EventType事件类型
EventListener监听及回调
EventDataBase回调时需要传递的参数
总结
前言
上一篇(事件中心1)中,简单解释了委托、事件、监听者,是用于管理项目运行过程中突发情况的产生和相应处理方法的手段。比如在仿真实验项目中,一旦按下急停按钮,或者传感器检测到过载等,这些情况都会带来一系列的后续,如电路短路、系统报警等。因此,每一个有一定规模的项目,需要建立一个事件管理中心,来管理和调用情况变化时需要执行的方法。否则不断地需要在Update()、FixedUpdate()中去if……else……非常消耗资源。
事件中心的结构
事件中心要解决的问题有3个:
1. 有哪些事件需要被关注?2. 这些事件与谁有关?3. 事件发生后要做出什么应对?
这三个问题相对应的就是1. 事件的类型;2. 事件的监听者;3. 回调(委托)
这里的键盘输入,使用到了新版的输入系统InputSystem,详细设置需要参照新版InputSystem。
EventManager事件管理器
EventManager是最主要的事件管理文档,继承单例(Single,详见单例)在这里要定义一些关于事件的添加、发送、删除等方法。基本结构如下:
public delegate void EventCallBack(EventDataBase database);
//定义一个委托,用于管理回调方法
public class EventManager : Single<EventManager> //继承单例
{
Dictionary<EventType, List<EventListener>> eventListener = new Dictionary<EventType, List<EventListener>>(); //定义存储事件的字典
//添加事件
public void AddEvent(EventType type,object listener,EventCallBack callBack)
{//事件类型,监听者(可以是任何类型),回调(委托)
if (listener == null)
return;
IfEventType(type);//判断字典里是否有该事件
eventListener[type].Add(new EventListener(listener, callBack)); //添加监听者到字典
}
private void IfEventType(EventType eventType)
{//判断字典里是否有该事件
if (!eventListener.ContainsKey(eventType))//如果字典没找到,就添加一个
eventListener.Add(eventType, new List<EventListener>());
}
//发送事件,通知所有监听者
public void SendEvent(EventType type, EventDataBase database)
{
if(eventListener.ContainsKey(type))//判断一下字典是否有该事件
{
List<EventListener> listeners = eventListener[type];//一旦事件对应上字典中的类型
foreach (EventListener listener in listeners)
{
listener.CallBack(database); //将该事件所对应的监听都回调一下,并且传参数
}
}
}
//删除事件的指定接收者listener
public void RemoveEventListener(EventType type, object listener)
{
List<EventListener> listeners;
if(eventListener.TryGetValue(type,out listeners))
{//尝试获取type类型,如果获取到了,就写到listenerList里
for(int i=0; i<listeners.Count;i++)
{
if (listeners[i] == listener)
{
listeners.RemoveAt(i);
return;
}
}
}
}
//删除事件,也会把这个事件的所有监听者都取消
public void RemoveEvent(EventType type)
{
if (eventListener.ContainsKey(type))
{
eventListener.Remove(type);
}
}
//清空所有事件
public void Clear()
{
eventListener.Clear();
}
}
在这段代码中使用到的EventDataBase、EventType、EventListener等类型,下面继续定义、说明:
EventType事件类型
使用一个枚举类型,列举所有需要关注的事件名称,这里仅仅举例了几个事件,需要其他事件还可以逐步加入完善:
public enum EventType
{
OnMouseInput=1001, //鼠标点击事件
OnKeyboardInput=1002, //键盘输入事件
OnPlayerFire = 1003, //发射子弹事件
OnPlayerMove=1004 //玩家移动事件
}
EventListener监听及回调
在EventListener类中定义了listener、callBack两个变量,并且需要一个带参构造,以便于调用。
public class EventListener
{//监听者,和它相应的回调
object listener;//监听可能为任何事件,所以用最大的类型Object
EventCallBack callBack;
public EventListener(object listener, EventCallBack callBack)
{//带参构造
Listener = listener;
CallBack = callBack;
}
//封装
public object Listener { get;}
public EventCallBack CallBack { get;}
}
EventDataBase回调时需要传递的参数
不同的回调函数需要传递的参数类型自然不同,因此设置一个传参数据的父类EventDataBase,以便于在管理器EventManager中统一调用。之后在实例使用中使用的实际参数类型只要都继承这个父类,向上转型即可。
//管理委托要传入的参数
public class EventDataBase
{//父类
}
public class EventDataPlayerMove:EventDataBase
{//在主角移动时,需要传入移动的坐标(XZ轴)
public Vector2 position;
}
public class EventDataMouseInput:EventDataBase
{//鼠标点击拖拽时,鼠标状态的传递
private EMouseInputKey key; //鼠标被按下的按键,从枚举中获取
private EMouseInputState state; //鼠标的状态,从枚举中获取
private Vector2 mousePosition; //鼠标的位置传递(XY转XZ轴)
}
public enum EMouseInputKey
{//鼠标被按下的按键,左、中、右,从枚举中获取
Left, Mid, Right,
}
public enum EMouseInputState
{//鼠标的状态:按下、长按、抬起
Down,Stay,Up
}
总结
1. 梳理一下事件中心定义的几个类、参数的关系:
2. 这只是一个定义事件的参考案例,在实际项目中还有更多的事件情况需要考虑;
3. 如何使用上面定义的这些方法,实现事件的注册、发送、回调等,请参照下一篇,实现鼠标拖拽、角色移动、发射子弹等几个功能。