UFL4-4——事件中心的事件名优化

事件中心中 事件名优化 指的是什么

目前我们通过 字符串 作为事件名来区分各事件
明显的缺点:若触发或监听时,事件名 字符串 拼写错误会导致无法正确监听或触发事件

制作思路和具体实现

将事件名使用枚举进行统一管理,例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
/// <summary>
/// 事件类型枚举
/// </summary>
public enum E_EventType
{
/// <summary>
/// 怪物死亡事件 —— 参数:Monster
/// </summary>
E_Monster_Dead,
/// <summary>
/// 玩家获取奖励 —— 参数:int
/// </summary>
E_Player_GetReward,
}

然后,将EventCenter​内所有使用到字符串事件名都改为使用枚举E_EventType​的

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

/// <summary>
/// 事件中心模块
/// </summary>
public class EventCenter : BaseManager<EventCenter>
{
private Dictionary<E_EventType, EventInfoBase> eventDic = new Dictionary<E_EventType, EventInfoBase>();

private EventCenter() { }

/// <summary>
/// 触发事件,同时传递一个参数
/// </summary>
/// <typeparam name="T">要传递的参数的类型</typeparam>
/// <param name="eventName">要触发的事件名字</param>
/// <param name="info">要传递的参数</param>
public void EventTrigger<T>(E_EventType eventName, T info)
{
//如果没有对象监听这个事件,则直接返回
if (!eventDic.ContainsKey(eventName))
return;
(eventDic[eventName] as EventInfo<T>).actions?.Invoke(info);
}

/// <summary>
/// 触发事件,不传递参数
/// </summary>
/// <param name="eventName">要触发的事件名字</param>
public void EventTrigger(E_EventType eventName)
{
//如果没有对象监听这个事件,则直接返回
if (!eventDic.ContainsKey(eventName))
return;
(eventDic[eventName] as EventInfo).actions?.Invoke();
}

/// <summary>
/// 添加事件监听者,监听方法需要参数
/// </summary>
/// <typeparam name="T">监听方法的参数类型</typeparam>
/// <param name="eventName">要监听的事件</param>
/// <param name="action">监听到事件后要执行的方法</param>
public void AddEventListener<T>(E_EventType eventName, UnityAction<T> action)
{
if (eventDic.ContainsKey(eventName))
(eventDic[eventName] as EventInfo<T>).actions += action;
else
{
//eventDic.Add(eventName, new UnityAction(action)); //不要这样写,会无法移除传入的方法
eventDic.Add(eventName, new EventInfo<T>(action));
}
}

/// <summary>
/// 添加事件监听者,该监听方法不需要参数
/// </summary>
/// <param name="eventName">要监听的事件</param>
/// <param name="action">监听到事件后要执行的方法</param>
public void AddEventListener(E_EventType eventName, UnityAction action)
{
if (eventDic.ContainsKey(eventName))
(eventDic[eventName] as EventInfo).actions += action;
else
{
//eventDic.Add(eventName, new UnityAction(action)); //不要这样写,会无法移除传入的方法
eventDic.Add(eventName, new EventInfo(action));
}
}

/// <summary>
/// 移除带参数的事件监听
/// </summary>
/// <typeparam name="T">监听方法的参数类型</typeparam>
/// <param name="eventName">要移除监听的事件</param>
/// <param name="action">要移除监听的方法</param>
public void RemoveEventListener<T>(E_EventType eventName, UnityAction<T> action)
{
if (eventDic.ContainsKey(eventName))
(eventDic[eventName] as EventInfo<T>).actions -= action;
}

/// <summary>
/// 移除无参事件监听
/// </summary>
/// <param name="eventName">要移除监听的事件</param>
/// <param name="action">要移除监听的方法</param>
public void RemoveEventListener(E_EventType eventName, UnityAction action)
{
if (eventDic.ContainsKey(eventName))
(eventDic[eventName] as EventInfo).actions -= action;
}

/// <summary>
/// 清除所有事件的监听
/// </summary>
public void Clear()
{
eventDic.Clear();
}

/// <summary>
/// 清除某一个事件的监听
/// </summary>
/// <param name="eventName"></param>
public void Clear(E_EventType eventName)
{
if (eventDic.ContainsKey(eventName))
eventDic.Remove(eventName);
}
}

使用示例

假设我们有下面的这些事件枚举

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/// <summary>
/// 事件类型枚举
/// </summary>
public enum E_EventType
{
/// <summary>
/// 怪物死亡事件 —— 参数:Monster
/// </summary>
E_Monster_Dead,
/// <summary>
/// 玩家获取奖励 —— 参数:int
/// </summary>
E_Player_GetReward,
/// <summary>
/// 测试用事件 —— 参数:无
/// </summary>
E_Test,
}

然后,我们即可使用枚举作为事件名,这样,我们就不再需要担心拼错事件名,而且事件名也更易于管理了

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>(E_EventType.E_Monster_Dead, PlayerWaitMonsterDeadDo);
EventCenter.Instance.AddEventListener(E_EventType.E_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>(E_EventType.E_Monster_Dead, PlayerWaitMonsterDeadDo);
EventCenter.Instance.RemoveEventListener(E_EventType.E_Test, Test);
}
}
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(E_EventType.E_Test);
}
}
}