UFL4-3——事件中心传递自定义参数
事件中心中 参数类型自定义 指的是什么
上节课我们通过万物之父 object
利用里式替换原则(父类装子类),实现了在事件中心中传递参数
但是使用 object
时,当传递值类型参数时,存在装箱拆箱的性能浪费
而这节课要讲解的 参数类型自定义 指的就是 在传递数据时,
参数类型可以根据需求自己定义,想传什么就传什么,而不是固定的 object
类型
制作思路和具体实现
制作思路:
想让传递的参数类型可变,并且想传什么就传什么,我们可以很自然的联想到使用泛型UnityAction<T>
来制作该功能
但是我们需要解决以下关键问题:字典容器中的 泛型委托 如何提前定好类型
我们不能直接让泛型类型的委托UnityAction<T>
作为Dictionary<TKey, TValue>
的值,因为不同泛型参数的委托不是一种类型的
而且我们也不能通过直接让EventCenter
变成泛型类的方法来解决这个问题,这样会破坏单例模式的唯一性
解决方案:里式替换原则(父类装子类)
声明一个EventInfo<T>
类,用来存储不同泛型参数的委托UnityAction<T>
,再让它继承一个不实现任何内容的抽象类EventInfoBase
这样EventInfoBase
即可装载不同泛型参数的EventInfo<T>
类,这样的父类可以作为Dictionary<TKey, TValue>
的值
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
|
public abstract class EventInfoBase { }
public class EventInfo<T> : EventInfoBase { public UnityAction<T> actions;
public EventInfo(UnityAction<T> action) { this.actions += action; } }
|
将EventInfoBase
作为eventDic
的值,将触发事件,添加事件和移除事件方法改为泛型方法,
方法内通过as
获取对应的EventInfo<T>
,再通过actions
来调用其中的UnityAction<T>
,来执行委托,或者向委托添加或移除方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| private Dictionary<string, EventInfoBase> eventDic = new Dictionary<string, EventInfoBase>();
public void EventTrigger<T>(string eventName, T info) { if (!eventDic.ContainsKey(eventName)) return; (eventDic[eventName] as EventInfo<T>).actions?.Invoke(info); }
public void AddEventListener<T>(string eventName, UnityAction<T> action) { if (eventDic.ContainsKey(eventName)) (eventDic[eventName] as EventInfo<T>).actions += action; else { eventDic.Add(eventName, new EventInfo<T>(action)); } }
public void RemoveEventListener<T>(string eventName, UnityAction<T> action) { if (eventDic.ContainsKey(eventName)) (eventDic[eventName] as EventInfo<T>).actions -= action; }
|
目前,我们写的方法,要求监听事件必须要带上一个参数,但监听事件不需要参数的情况也很多,因此我们需要添加一个无需参数的方法
声明一个不带泛型的EventInfo
,用来包裹 UnityAction
,同样继承EventInfoBase
,便于装载到eventDic
字典内
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
|
public abstract class EventInfoBase { }
public class EventInfo : EventInfoBase { public UnityAction actions;
public EventInfo(UnityAction action) { this.actions += action; } }
|
然后,在EventCenter
内声明对应的不需要泛型的触发无参事件方法,添加和移除无参监听事件方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| private Dictionary<string, EventInfoBase> eventDic = new Dictionary<string, EventInfoBase>();
public void EventTrigger(string eventName) { if (!eventDic.ContainsKey(eventName)) return; (eventDic[eventName] as EventInfo).actions?.Invoke(); }
public void AddEventListener(string eventName, UnityAction action) { if (eventDic.ContainsKey(eventName)) (eventDic[eventName] as EventInfo).actions += action; else { eventDic.Add(eventName, new EventInfo(action)); } }
public void RemoveEventListener(string eventName, UnityAction action) { if (eventDic.ContainsKey(eventName)) (eventDic[eventName] as EventInfo).actions -= action; }
|
使用示例
经过以上改造,我们即可让事件中心传递自定义类型的参数或者不传递参数,并且监听方法拿到的参数也不需要再转换类型了
但是要注意,一个事件名只能传递一种参数或者不传递参数,因此绝对不可以向一个事件名使用不同泛型类型的监听方法!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| using UnityEngine;
public class Player : MonoBehaviour { private void Awake() { EventCenter.Instance.AddEventListener<Monster>("MonsterDead", PlayerWaitMonsterDeadDo); EventCenter.Instance.AddEventListener("Test", Test); }
public void Test() { print("无参事件监听者"); }
public void PlayerWaitMonsterDeadDo(Monster info) { Debug.Log("怪物名为:" + info.monsterName + ",怪物ID" + info.monsterID); Debug.Log("玩家得到奖励"); }
public void OnDestroy() { EventCenter.Instance.RemoveEventListener<Monster>("MonsterDead", PlayerWaitMonsterDeadDo); EventCenter.Instance.RemoveEventListener("Test", Test); } }
|
触发事件时,可以传入指定类型的对象或者不传入事件
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| using UnityEngine;
public class Monster : MonoBehaviour { public string monsterName = "123123123"; public int monsterID = 1;
public void Dead() { Debug.Log("怪物死亡了"); EventCenter.Instance.EventTrigger<Monster>("MonsterDead", this); } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| using System; using UnityEngine;
public class Main : MonoBehaviour { void Update() { if (Input.GetKeyDown(KeyCode.X)) { GameObject.Find("Monster").GetComponent<Monster>().Dead(); EventCenter.Instance.EventTrigger("Test"); } } }
|
按下X键输出:
可传递自定义类型的参数的事件中心具体代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147
| using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.Events;
public abstract class EventInfoBase { }
public class EventInfo<T> : EventInfoBase { public UnityAction<T> actions;
public EventInfo(UnityAction<T> action) { this.actions += action; } }
public class EventInfo : EventInfoBase { public UnityAction actions;
public EventInfo(UnityAction action) { this.actions += action; } }
public class EventCenter : BaseManager<EventCenter> { private Dictionary<string, EventInfoBase> eventDic = new Dictionary<string, EventInfoBase>();
private EventCenter() { }
public void EventTrigger<T>(string eventName, T info) { if (!eventDic.ContainsKey(eventName)) return; (eventDic[eventName] as EventInfo<T>).actions?.Invoke(info); }
public void EventTrigger(string eventName) { if (!eventDic.ContainsKey(eventName)) return; (eventDic[eventName] as EventInfo).actions?.Invoke(); }
public void AddEventListener<T>(string eventName, UnityAction<T> action) { if (eventDic.ContainsKey(eventName)) (eventDic[eventName] as EventInfo<T>).actions += action; else { eventDic.Add(eventName, new EventInfo<T>(action)); } }
public void AddEventListener(string eventName, UnityAction action) { if (eventDic.ContainsKey(eventName)) (eventDic[eventName] as EventInfo).actions += action; else { eventDic.Add(eventName, new EventInfo(action)); } }
public void RemoveEventListener<T>(string eventName, UnityAction<T> action) { if (eventDic.ContainsKey(eventName)) (eventDic[eventName] as EventInfo<T>).actions -= action; }
public void RemoveEventListener(string eventName, UnityAction action) { if (eventDic.ContainsKey(eventName)) (eventDic[eventName] as EventInfo).actions -= action; }
public void Clear() { eventDic.Clear(); }
public void Clear(string eventName) { if (eventDic.ContainsKey(eventName)) eventDic.Remove(eventName); } }
|