Unity 事件中心(EventCenter)
一、概念
事件中心(EventCenter) 是 Unity 项目中常用的 全局消息总线,用于:
- 解耦对象间的逻辑依赖
- 实现观察者模式
- 管理全局事件订阅与触发
二、核心接口
| 方法 | 功能 | 说明 |
|---|---|---|
AddEventListener(string name, UnityAction<object> action) |
注册事件监听 | 将回调函数添加到指定事件 |
RemoveEventListener(string name, UnityAction<object> action) |
移除事件监听 | 注销回调,避免内存泄漏 |
EventTrigger(string name, object obj) |
触发事件 | 执行指定事件的所有回调函数 |
Clear() |
清空事件 | 场景切换或全局重置时使用 |
三、代码实现
事件中心(EventCenter.cs)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;
/// <summary>
/// 事件中心 单例模式对象
/// 1.Dictionary
/// 2.委托
/// 3.观察者设计模式
/// </summary>
public class EventCenter
{
private static EventCenter instance;
public static EventCenter Instance
{
get
{
if (instance == null)
{
instance = new EventCenter();
}
return instance;
}
}
// key——事件的名字(比如:怪物死亡 玩家死亡 通过 等等)
// value——对应的是 监听这个事件 对应的委托函数们
private Dictionary<string, UnityAction<object>> eventDic = new Dictionary<string, UnityAction<object>>();
private EventCenter() { }
/// <summary>
/// 添加事件监听
/// </summary>
/// <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);
}
}
/// <summary>
/// 移除对应的事件监听
/// </summary>
/// <param name="name">事件的名字</param>
/// <param name="action">对应之前添加的委托函数</param>
public void RemoveEventListener(string name, UnityAction<object> action)
{
// 有没有对应的事件监听
// 有的情况
if (eventDic.ContainsKey(name))
{
eventDic[name] -= action;
}
}
/// <summary>
/// 事件触发
/// </summary>
/// <param name="name">哪一个名字的事件出发了</param>
public void EventTrigger(string name, object obj)
{
// 有没有对应的事件监听
// 有的情况
if (eventDic.ContainsKey(name))
{
eventDic[name]?.Invoke(obj);
}
}
/// <summary>
/// 清空事件中心
/// 主要用在 场景切换时
/// </summary>
public void Clear()
{
eventDic.Clear();
}
}
四、完整示例
- 示例把AddEventListener写在了Awake中,是因为Monster在Start里执行了Dead,事件监听的注册要早于事件触发才不会出错
Monster.cs
public class Monster : MonoBehaviour
{
public string monsterName;
private void Start()
{
monsterName = "哥布林1";
Dead();
}
public void Dead()
{
Debug.Log("怪物死亡");
EventCenter.Instance.EventTrigger("MonsterDead", this);
}
}
Player.cs
public class Player : MonoBehaviour
{
private void Awake()
{
EventCenter.Instance.AddEventListener("MonsterDead", OnMonsterDead);
}
private void OnDestroy()
{
EventCenter.Instance.RemoveEventListener("MonsterDead", OnMonsterDead);
}
private void OnMonsterDead(object info)
{
Monster monster = info as Monster;
Debug.Log("玩家得到奖励:" + monster.monsterName);
}
}
Task.cs(任务系统示例)
private void Awake()
{
EventCenter.Instance.AddEventListener("MonsterDead", OnMonsterDead);
}
private void OnDestroy()
{
EventCenter.Instance.RemoveEventListener("MonsterDead", OnMonsterDead);
}
private void OnMonsterDead(object info)
{
Monster monster = info as Monster;
Debug.Log("任务记录怪物死亡:" + monster.monsterName);
}
五、优化装箱拆箱问题以及实现无参数重载
事件中心(EventCenter.cs)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;
//解决Dictionary不能使用泛型T
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;
}
}
/// <summary>
/// 事件中心 单例模式对象
/// 1.Dictionary
/// 2.委托
/// 3.观察者设计模式
/// 4.泛型
/// </summary>
public class EventCenter
{
private static EventCenter instance;
public static EventCenter Instance
{
get
{
if (instance == null)
{
instance = new EventCenter();
}
return instance;
}
}
// key——事件的名字(比如:怪物死亡 玩家死亡 通过 等等)
// value——对应的是 监听事件类 的接口(通过里氏替换原则可以强转为 监听事件类)
private Dictionary<string, IEventInfo> eventDic = new Dictionary<string, IEventInfo>();
private EventCenter() { }
/// <summary>
/// 添加事件监听(需要参数的)
/// </summary>
/// <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));
}
}
/// <summary>
/// 添加事件监听(不需要参数的)
/// </summary>
/// <param name="name">事件的名字</param>
/// <param name="action">准备用来处理事件 的委托函数</param>
public void AddEventListener(string name, UnityAction action)
{
// 有没有对应的事件监听
// 有的情况
if (eventDic.ContainsKey(name))
{
(eventDic[name] as EventInfo).actions += action;
}
// 没有的情况
else
{
eventDic.Add(name, new EventInfo(action));
}
}
/// <summary>
/// 移除对应的事件监听(需要参数的)
/// </summary>
/// <param name="name">事件的名字</param>
/// <param name="action">对应之前添加的委托函数</param>
public void RemoveEventListener<T>(string name, UnityAction<T> action)
{
// 有没有对应的事件监听
// 有的情况
if (eventDic.ContainsKey(name))
{
(eventDic[name] as EventInfo<T>).actions -= action;
}
}
/// <summary>
/// 移除对应的事件监听(不需要参数的)
/// </summary>
/// <param name="name">事件的名字</param>
/// <param name="action">对应之前添加的委托函数</param>
public void RemoveEventListener(string name, UnityAction action)
{
// 有没有对应的事件监听
// 有的情况
if (eventDic.ContainsKey(name))
{
(eventDic[name] as EventInfo).actions -= action;
}
}
/// <summary>
/// 事件触发(需要参数的)
/// </summary>
/// <param name="name">哪一个名字的事件触发了</param>
/// <param obj="obj">传入回调的本对象</param>
public void EventTrigger<T>(string name, T obj)
{
// 有没有对应的事件监听
// 有的情况
if (eventDic.ContainsKey(name))
{
if ((eventDic[name] as EventInfo<T>).actions != null)
{
(eventDic[name] as EventInfo<T>).actions.Invoke(obj);
}
}
}
/// <summary>
/// 事件触发(不需要参数的)
/// </summary>
/// <param name="name">哪一个名字的事件触发了</param>
public void EventTrigger(string name)
{
// 有没有对应的事件监听
// 有的情况
if (eventDic.ContainsKey(name))
{
if ((eventDic[name] as EventInfo).actions != null)
{
(eventDic[name] as EventInfo).actions.Invoke();
}
}
}
/// <summary>
/// 清空事件中心
/// 主要用在 场景切换时
/// </summary>
public void Clear()
{
eventDic.Clear();
}
}
六、完整示例
Monster.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Monster : MonoBehaviour
{
public string monsterName;
private void Start()
{
monsterName = "怪物1";
Dead();
}
/// <summary>
/// 死亡方法
/// </summary>
public void Dead()
{
Debug.Log("怪物死亡");
EventCenter.Instance.EventTrigger<Monster>("MonsterDead", this);
EventCenter.Instance.EventTrigger("Win");
}
}
Player.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Player : MonoBehaviour
{
private void Awake()
{
EventCenter.Instance.AddEventListener<Monster>("MonsterDead", MonsterDeadDo);
EventCenter.Instance.AddEventListener("Win", Win);
}
public void MonsterDeadDo(Monster info)
{
Debug.Log("玩家得到奖励" + info.monsterName);
}
public void Win()
{
Debug.Log("玩家胜利");
}
private void OnDestroy()
{
EventCenter.Instance.RemoveEventListener<Monster>("MonsterDead", MonsterDeadDo);
EventCenter.Instance.RemoveEventListener("Win", Win);
}
}

浙公网安备 33010602011771号