Event Center Model In Unity

这篇文章将在Unity中实现事件中心模块,在此之前我先引入一个情境:
当玩家打败Boss时,Boss会掉落物品、同时会播放玩家胜利动画、如果是第一次击败Boss还会进行成就播报、NPC会为你庆祝(甚至开一场party)……

Q1:天啊!这么多的事情!??!弓虽!是我的话要在好多个脚本中写上好多好多逻辑,我还会为怪物、玩家、成就、NPC添加一堆状态,这样让除自己之外的脚本也知道自己发生了什么改变,想想就头疼……
A:无需担心!读者,或许我该称呼你为元读者?本文就是告诉你解耦的方式的。:)
Q2:作者,哦不,元作者,解耦是啥?
A:解耦,用我的话说,就是把莲藕的丝切断,如果能弄干净就好了,不然吃莲藕的时候还得吃一脸丝。在程序里,就是各个脚本负责某个特定功能,不要插足别的事情,到时候在脚本间的决策阶段会很麻烦,脚本和脚本打架,就像《千与千寻》中锅炉爷爷说的”不要抢走别人的工作“,哈哈哈,跑题了。
A:在此之前,我将介绍一下观察者模式,在我上面举的例子当中,有怪物、成就、玩家和NPC,其中一个部分发生变化,其他的部分也要发生改变。这时,我就会建一个中转站,怪物死了,叫个信使告诉我”怪物死了“,然后这个中转站再告诉其他地方”怪物死了“这个消息,然后各处都要求我做一些事情——各个地方告诉我的事情,我会在收到要执行这件事的消息后才去执行。这个中转站就是今天要介绍的事件中心


事件中心需要具备:

  • 添加各个地方要求的事件
  • 移除某个地方要求的事件
  • 条件满足时执行事件
  • 事件中心用于存储事件容器
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
//继承了之前的可以挂载在对象上的单例模式基类
public class EventCenter : SingletonMonoBase<EventCenter>
{
//存储监听函数的容器
private Dictionary<string, UnityAction<object>> eventDic = new Dictionary<string, UnityAction<object>>();
//添加监听函数的方法
public void AddListener(string name,UnityAction<object> func)
{
if (eventDic.ContainsKey(name))
{
eventDic[name] += func;
}
else
{
eventDic.Add(name, func);
}
}
//移除监听函数的方法
public void RemoveListener(string name)
{
if (eventDic.ContainsKey(name))
eventDic.Remove(name);
return;
}
//移除所有的监听函数
public void RemoveAllListener()
{
eventDic = null;
}
//分发(触发)事件的函数
public void EventTrigger(string name,object info)
{
if (eventDic.ContainsKey(name))
{
eventDic[name].Invoke(info);
}
else
{
Debug.Log("来自事件中心:EventTrigger()未能找到要触发的事件");
}
}
}

Q1:为什么字典的值为UnityAction<object>
A:UnityAction是Unity提供的委托类。(1)有参数是因为我们可能希望在分发事件的时候,别的地方要告诉我们一些信息,这样一来我们才能根据它们提供的信息知道要怎么做这些事件。(2)参数类型为object是因为它是万物之父,用它作为参数,什么都可以传进去,无论是自定义类还是数组等数据结构类,都不在话下。
Q2:可以介绍一下如何使用事件中心吗?
A:正合我意:)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
//玩家类
public class Player : MonoBehaviour
{
private void Start()
{
EventCenter.GetInstance().AddListener("怪物死了",DebugWaitingForMonsterDied);
}
public void DebugWaitingForMonsterDied(Object info)
{
Debug.Log($"怪物死了,该播放动画了,这是怪物的遗言{info}");
}
}

//怪物类
public class Monster
{
public void Died()
{
EventCenter.GetInstance().EventTrigger("怪物死了","我死得不甘心啊");
}
}

好的,今天到此为止…… :)