事件中心
观察者模式
大概理解就是一种一对多的关系
当这个特定对象的状态发生改变的时候
所有依赖于这个对象的对象们都会收到改变的信息
然后做出对应的反应
事件中心是什么
我们知道框架里可能有很多个不同的管理器
但是这些管理器肯定没办法做到完全独立
彼此之间还是会有一些逻辑处理和数据交换
同理 游戏里有很多不同的对象 对象之间也涉及到交流
假如互相引用的话代码看起来就不太好看
所以我们就想到了交给第三方来处理
也就是事件中心
作为发起人 我告诉事件中心什么事情发生了
作为委托人 我告诉事件中心当某件事发生时我会去做什么
然后事件中心就开始监听 监听到发起人说某件事发生了
便会告诉委托人你现在该做啥了
这就是事件中心的工作原理
PS:这里的坑在于监听对象是否有限制的问题
事件中心的代码实现
我们依然选择了字典作为我们的存放对象
string作为key 也就是事件名
而事件作为我们的值
关于这里事件的封装其实比较没有那么复杂
其实就是包装了一层接口 然后做里氏替换
关键是为什么要这样做呢?
事件中心这个类是单例对吧 他是唯一的 那么给事件中心这个类加上泛型就会很奇怪
因为它只会初始化一次 你只能传一次类型
例如说你想在类里直接用UnityAction<T> 哎 你发现你还得给单例加上泛型
所以这里我们在外面小小封装了一下
不用object很明显 就是为了避免装箱拆箱
using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.Events; public interface I_EventGeneric { } public class EventGeneric<T> : I_EventGeneric { public UnityAction<T> actions; public EventGeneric(UnityAction<T> action) { actions += action; } } public class EventGeneric : I_EventGeneric { public UnityAction actions; public EventGeneric(UnityAction action) { actions += action; } } /// <summary> /// 事件中心 单例 /// 事件触发要晚于事件监听 /// </summary> public class EventCenter : BaseManager<EventCenter> { //存放事件的容器 Key是事件名 value是监听事件对应的委托函数们 private Dictionary<string, I_EventGeneric> eventDic = new Dictionary<string, I_EventGeneric>(); /// <summary> /// 添加事件监听 /// </summary> /// <param name="name">事件名</param> /// <param name="action">处理事件的委托函数</param> public void AddEventListener<T>(string name, UnityAction<T> action) { //有没有对应的事件监听 if(eventDic.ContainsKey(name)) { //有就直接添加 (eventDic[name] as EventGeneric<T>).actions += action; } else { //没有就要创建 eventDic.Add(name, new EventGeneric<T>(action)); } } /// <summary> /// 移除事件监听 /// </summary> /// <param name="name">移除的事件名</param> /// <param name="action">事件添加的委托函数</param> public void RemoveEventListener<T>(string name, UnityAction<T> action) { if (eventDic.ContainsKey(name)) { (eventDic[name] as EventGeneric<T>).actions -= action; } //销毁时调用 OnDestroy() } /// <summary> /// 事件触发 /// </summary> /// <param name="name">触发的事件名</param> public void EventTrigger<T>(string name, T info) { if (eventDic.ContainsKey(name) && (eventDic[name] as EventGeneric<T>).actions != null) { (eventDic[name] as EventGeneric<T>).actions.Invoke(info); } } /// <summary> /// 清空事件中心 防止场景切换时溢出 /// </summary> public void Clear() { eventDic.Clear(); } }
事件中心的使用
假设现在我们有一个怪物类 作为事件的发起者 死亡的时候进行触发
有一个任务类和一个玩家类 分别委托了怪物死亡的时候要做的事情
具体实现如下
using System.Collections; using System.Collections.Generic; using UnityEngine; public class Task : MonoBehaviour { void Awake() { EventCenter.GetInstance().AddEventListener<Monster>("MonsterDie", TaskDone); } void OnDestroy() { EventCenter.GetInstance().RemoveEventListener<Monster>("MonsterDie", TaskDone); } public void TaskDone(Monster info) { Debug.Log("任务完成"); } }
using System.Collections; using System.Collections.Generic; using UnityEngine; public class Monster : MonoBehaviour { void Start() { Die(); } public void Die() { Debug.Log("怪物死亡"); //触发事件 EventCenter.GetInstance().EventTrigger("MonsterDie", this); } }
using System.Collections; using System.Collections.Generic; using UnityEngine; public class Player : MonoBehaviour { // Start is called before the first frame update void Awake() { EventCenter.GetInstance().AddEventListener<Monster>("MonsterDie", GetBonus); } void OnDestroy() { EventCenter.GetInstance().RemoveEventListener<Monster>("MonsterDie", GetBonus); } public void GetBonus(Monster info) { Debug.Log(info.gameObject.name +"死了,增加金币"); } }