假设怪物死亡后,需要做三件事:player得到奖励,更新任务记录,其他包括成就系统、刷新怪物等待,有前后联系,最简单的方法就是找到脚本挂在的对象,然后得到脚本,最后调用脚本中的函数,但这样会让程序的耦合性太强,因此换一个做法,当怪物死亡的时候不和其他方法直接进行关联,而是通知事件中心派发一个事件,将该事件关联的行为(即监听 )进行调用。
public class EventMgr : BaseManager<EventMgr > {
// key —— 事件的名字
// value —— 监听的事件对应的委托函数们
// 通过UnityAction<object>可以用一个类型传任何参数(数组也可以用object表示)
private Dictionary<string, UnityAction<object>> eventDic = new Dictionary<string, UnityAction<object>>();
// <param name="name"> 事件的名字</param>
// <param name="action"> 处理事件的委托函数</param>
public void AddEventListener(string name, UnityAction<object> action) {
if (eventDic.ContainsKey(name)) {
eventDic[name] += action;
} else {
eventDic.Add(name, action);
}
}
// <param name="name"> 触发的事件</param>
public void EventTrigger(string name, object params) {
if (eventDic.ContainsKey(name)) {
eventDic[name].Invoke(params);
}
}
// 移除委托函数
public void RemoveEventListener(string name, UnityAction<object> action) {
if (eventDic.ContansKey(name)) {
eventDic[name] -= action;
}
}
public void ClearAllListener() {
// eventDic[name] = null;
eventDic.Clear();
}
}
public class Monster : MonoBehaviour {
public string name = "monster";
void Start() {
Dead();
}
void Dead() {
Debug.Log("怪物死亡");
// 其他对象想在怪物死亡后的行为,比如
// 1、玩家得到奖励
// 2、更新任务记录
// 3、其他(比如成就系统,副本继续刷怪等)
// TODO.....
// 分发事件
EventMgr .GetInstance().EventTrigger("MonsterDead", this);
}
}
// -----------------------------------------------
public class Player : MonoBehaviour {
void Start() {
EventMgr .GetInstance().AddEventListerner("MonsterDead", MonsterDeadDo);
}
public void MonsterDeadDo(object info) {
Debug.Log("玩家得到奖励");
}
void OnDestroy() {
EventMgr .GetInstance().RemoveEventListener("MonsterDead", MonsterDeadDo);
}
}
// -----------------------------------------------
public class Task : MonoBehaviour {
void Start() {
EventMgr .GetInstance().AddEventListerner("MonsterDead", TaskWaitMonsterDeadDo);
}
public void TaskWaitMonsterDeadDo(object info) {
Debug.Log("任务记录");
}
void OnDestroy() {
EventMgr .GetInstance().RemoveEventListener("MonsterDead", TaskWaitMonsterDeadDo);
}
}
// -----------------------------------------------
public class Other : MonoBehaviour {
void Start() {
EventMgr .GetInstance().AddEventListerner("MonsterDead", OtherWaitMonsterDeadDo);
}
public void OtherWaitMonsterDeadDo(object info) {
Debug.Log("其他要做的事");
}
void OnDestroy() {
EventMgr .GetInstance().RemoveEventListener("MonsterDead", OtherWaitMonsterDeadDo);
}
}
如果要优化一下装箱拆箱的问题,可以通过里氏替换以及泛型原则进行一个骚操作,如果不需要参数,通过重载
public interface IEventInfo {
}
public class EventInfo<T> : IEventInfo {
public UnityAction<T> actions;
public EventInfo( UnityAction<T> action) {
actions += action;
}
}
public class EventInfo : IEventInfo {
public UnityAction actions;
public EventInfo( UnityAction action) {
actions += action;
}
}
public class EventMgr : BaseManager<EventMgr > {
// key —— 事件的名字
// value —— 监听的事件对应的委托函数们
// 通过UnityAction<object>可以用一个类型传任何参数(数组也可以用object表示)
private Dictionary<string, IEventInfo > eventDic = new Dictionary<string, IEventInfo >();
// <param name="name"> 事件的名字</param>
// <param name="action"> 处理事件的委托函数</param>
public void AddEventListener<T>(string name, UnityAction<T> action) {
if (eventDic.ContainsKey(name)) {
(eventDic[name] as EventInfo<T>).actions += action;
} else {
eventDic.Add(name, new EventInfo<T>(action));
}
}
public void AddEventListener(string name, UnityAction action) {
if (eventDic.ContainsKey(name)) {
(eventDic[name] as EventInfo).actions += action;
} else {
eventDic.Add(name, new EventInfo(action));
}
}
// <param name="name"> 触发的事件</param>
public void EventTrigger<T>(string name, T params) {
if (eventDic.ContainsKey(name)) {
if ((eventDic[name] as EventInfo<T>).actions != null)
(eventDic[name] as EventInfo<T>).actions.Invoke(params);
}
}
public void EventTrigger(string name) {
if (eventDic.ContainsKey(name)) {
if ((eventDic[name] as EventInfo).actions != null)
(eventDic[name] as EventInfo).actions.Invoke();
}
}
// 移除委托函数
public void RemoveEventListener<T>(string name, UnityAction<T> action) {
if (eventDic.ContansKey(name)) {
(eventDic[name] as EventInfo<T>).actions -= action;
}
}
public void RemoveEventListener(string name, UnityAction action) {
if (eventDic.ContansKey(name)) {
(eventDic[name] as EventInfo).actions -= action;
}
}
public void ClearAllListener() {
// eventDic[name] = null;
eventDic.Clear();
}
}