Unity框架之事件中心模块

本文引入一种常见的设计模式:观察者模式。

事件中心模块作用

在玩游戏时经常有这样的场景,你打死了一只怪:怪物爆金币、角色经验提升、角色天赋升级。假如你是游戏开发者,会怎么处理这些逻辑?我最先的想法是这样的:写一个void MonsterDead(){},在里面添加各种方法,GetMoney()、PlayerUpdate()。
这样写貌似也没问题,但是当逻辑多起来、维护起来就比较困难了,又杂又乱。用专业的语言来说,就是我们“代码耦合性高”。因此引入事件中心模块。

思路

在军队中,有着指挥部。我们是不是也可以在代码里建立个“指挥部”,把各种命令都交给指挥部来做?
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
//既然是指挥部,那就只有一个,继承单例模式基类
public class EventMgr : SingletonBase<EventMgr>
{
//我们用字典来存储,思路是,用string来存储游戏里的事件,UnityAction执行触发事件后的一系列方法,比如爆金币、玩家升级
private Dictionary<string,UnityAction> eventmgr = new Dictionary<string,UnityAction>();
//我们写事件监听函数
public void AddEventListener(string name,UnityAction action)
{
if (eventmgr.ContainsKey(name))
{
eventmgr[name] += action;
}
else
{
eventmgr.Add(name, action);
}
}
//游戏事件触发后执行的一系列逻辑
public void EventTrigger(string name)
{
if (!eventmgr.ContainsKey(name))
{
Debug.Log("指定方法不存在!");
}
else
{
eventmgr[name].Invoke();
}
}
}
//我们假设有个怪物类,触发事件“MonsterDead”
public class Monster : MonoBehaviour
{
private void Start()
{
EventMgr.GetInstance().EventTrigger("MonsterDead");
}
}
//之后我们玩家,只需要往这个事件里添加方法逻辑就好,往MonsterDead事件里添加函数MonsterDeadDo
public class Player : MonoBehaviour
{
void Start()
{
EventMgr.GetInstance().AddEventListener("MonsterDead", MonsterDeadDo);
}

/// <summary>
/// 怪物死时要做些什么
/// </summary>
public void MonsterDeadDo()
{
Debug.Log("玩家得奖励");
}
}

就这样,我们的基础事件中心模块就写好了。

进阶优化版

之前写了个简单的事件管理中心,但它其实是有局限性的,只能传入无参的函数,对于有参的函数就不行了,于是有了v2.0版本。
最先想到的是,多声明几个字典,但这样就破坏了管理中心的理念,应该是只有一个字典、能装载不同的函数才对。那么新的思路就是把有参的、无参的都封装成一个,继承同一个接口

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
using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;

public class GameEventManager : SingleTon<GameEventManager>
{
private interface IEventHelp
{

}

private class EventHelp : IEventHelp
{
public event UnityAction Action;

public void AddCall(UnityAction action)
{
Action += action;
}

public void Call()
{
Action?.Invoke();
}

public void RemoveCall(UnityAction action)
{
Action -= action;
}
}

private class EventHelp<T> : IEventHelp
{
public event UnityAction<T> Action;

public void AddCall(UnityAction<T> action)
{
Action += action;
}

public void Call()
{
Action?.Invoke(default(T));
}

public void RemoveCall(UnityAction<T> action)
{
Action -= action;
}
}

private Dictionary<string, IEventHelp> eventManager = new Dictionary<string, IEventHelp>();

// 添加事件监听
public void AddEventListening(string eventName, UnityAction action)
{
if (!eventManager.ContainsKey(eventName))
{
eventManager[eventName] = new EventHelp();
}
((EventHelp)eventManager[eventName]).AddCall(action);
}

// 添加带参数的事件监听
public void AddEventListening<T>(string eventName, UnityAction<T> action)
{
if (!eventManager.ContainsKey(eventName))
{
eventManager[eventName] = new EventHelp<T>();
}
((EventHelp<T>)eventManager[eventName]).AddCall(action);
}

// 删除事件监听
public void RemoveEvent(string eventName, UnityAction action)
{
if (eventManager.ContainsKey(eventName))
{
var eventHelp = eventManager[eventName] as EventHelp;
if (eventHelp != null)
{
eventHelp.RemoveCall(action);
}
}
}

// 删除带参数的事件监听
public void RemoveEvent<T>(string eventName, UnityAction<T> action)
{
if (eventManager.ContainsKey(eventName))
{
var eventHelp = eventManager[eventName] as EventHelp<T>;
if (eventHelp != null)
{
eventHelp.RemoveCall(action);
}
}
}

// 触发事件
public void InvokeEvent(string eventName)
{
if (eventManager.ContainsKey(eventName))
{
var eventHelp = eventManager[eventName] as EventHelp;
if (eventHelp != null)
{
eventHelp.Call();
}
}
}

// 触发带参数的事件
public void InvokeEvent<T>(string eventName, T param)
{
if (eventManager.ContainsKey(eventName))
{
var eventHelp = eventManager[eventName] as EventHelp<T>;
if (eventHelp != null)
{
eventHelp.Call();
}
}
}
}