UFL4-2——事件中心传递参数

事件中心中传递参数指的是什么

希望在触发事件时传递数据,比如

  • 怪物死亡时,将怪物信息传递出去
  • 获取奖励时,将奖励信息传递出去

等等

传递数据的主要目的是,我们可以在各系统、模块、对象中获取到我们希望获取的有用信息

制作思路和具体实现

我们目前触发事件,是通过执行委托中存储的函数来执行各系统对应的逻辑,那么需要传递参数,我们很自然的联想到应该从委托入手

但是参数的类型可能有多种多样,我们可以采用万物之父 object​ 利用里式替换原则,父类容器装载子类对象的方式来传递参数

因此,将存储事件的委托字典eventDic​的值从UnityAction​转为使用UnityAction<object>​,
其他相关方法AddEventListener​和RemoveEventListener​也修改为使用UnityAction<object>​参数,
而触发事件的方法EventTrigger​就需要额外传入一个object​参数,在执行委托时将参数传进去

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
private Dictionary<string, UnityAction<object>> eventDic = new Dictionary<string, UnityAction<object>>();

private EventCenter() { }

// 触发事件
public void EventTrigger(string eventName, object info = null)
{
//如果没有对象监听这个事件,则直接返回
if (!eventDic.ContainsKey(eventName))
return;
eventDic[eventName]?.Invoke(info);
}

// 添加事件监听者
public void AddEventListener(string eventName, UnityAction<object> action)
{
if (eventDic.ContainsKey(eventName))
eventDic[eventName] += action;
else
{
//eventDic.Add(eventName, new UnityAction(action)); //不要这样写,会无法移除传入的方法
eventDic.Add(eventName, null);
eventDic[eventName] += action;
}
}

// 移除事件监听
public void RemoveEventListener(string eventName, UnityAction<object> action)
{
if (eventDic.ContainsKey(eventName))
eventDic[eventName] -= action;
}

使用示例

这样 Monster​ 类就可以在触发事件时,将自己作为参数传递到各个监听者,监听者即可获取怪物的消息

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("MonsterDead", this);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
using UnityEngine;

public class Player : MonoBehaviour
{
private void Awake()
{
EventCenter.Instance.AddEventListener("MonsterDead", PlayerWaitMonsterDeadDo);
}

public void PlayerWaitMonsterDeadDo(object info)
{
Monster monster = info as Monster;
Debug.Log("怪物名为:" + monster.monsterName + ",怪物ID" + monster.monsterID);
Debug.Log("玩家得到奖励");
}

public void OnDestroy()
{
EventCenter.Instance.RemoveEventListener("MonsterDead", PlayerWaitMonsterDeadDo);
}
}

输出:image

存在的问题

使用 object​ 进行参数传递,当传递值类型数据时,会存在装箱拆箱,增加性能开销

可传入参数的事件中心具体代码

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

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

private EventCenter() { }

/// <summary>
/// 触发事件
/// </summary>
/// <param name="eventName">要触发的事件名字</param>
public void EventTrigger(string eventName, object info = null)
{
//如果没有对象监听这个事件,则直接返回
if (!eventDic.ContainsKey(eventName))
return;
eventDic[eventName]?.Invoke(info);
}

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

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

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

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