事件中心是什么
事件中心是 Unity 游戏开发中常用的架构设计,它基于观察者模式 或 发布-订阅模式 ,通过委托 和事件 构建的一种消息管理系统。主要用于降低代码耦合度 ,实现模块间的松耦合通信的消息处理系统能大幅提升代码的可维护性和扩展性,允许不同脚本在不直接引用彼此的情况下进行交互。
作用
- 解耦代码,减少直接依赖
传统方式:A 脚本调用 B 脚本的方法,需要 GetComponent<B>() 或持有 B 的引用。
事件中心方式:A 触发事件,B 监听事件,两者无需互相知道对方存在。
- 全局通信
任何脚本都可以监听或触发事件,适合跨场景、跨系统的通信(如UI更新、游戏状态变化、敌人死亡通知等)。
- 动态管理事件
可以随时添加/移除事件监听,避免硬编码调用关系。
适合动态场景(如玩家死亡后取消某些监听)。
- 支持多参数传递
事件可以携带数据(如 int damage、string playerName、Vector3 position 等)。
应用场景
1. 游戏逻辑(如敌人死亡、任务完成)
2. UI交互(如按钮点击、数据更新)
3. 场景切换(如清理事件缓存)
实现方式
EventCenter 代码可直接食用,无需挂载在场景中,可供全局使用。
该消息中心设置了一个不限返回数据类型的委托 params object[] msg;
同时将消息名和对应的回调方法以键值对的方式存储在字典中 Dictionary<string, EventHandler>;
消息中心除了在触发相应事件的时候调用相应的回调函数,还能传回不同类型、数量的数据。
cs
using UnityEngine;
using System.Collections.Generic;
public static class EventCenter
{
// 事件委托定义,用于回调函数,参数为object数组,返回值为空
public delegate void EventHandler(params object[] msg);
// 消息字典
private static Dictionary<string, EventHandler> messageDic = new Dictionary<string, EventHandler>();
// 注册消息监听
public static void AddListener(string msgName, EventHandler eventHandler)
{
if (messageDic.ContainsKey(msgName))
{
messageDic[msgName] += eventHandler;
}
else
{
messageDic.Add(msgName, eventHandler);
}
}
// 注销消息监听
public static void RemoveListener(string msgName, EventHandler eventHandler)
{
if (messageDic.ContainsKey(msgName))
{
messageDic[msgName] -= eventHandler;
if (messageDic[msgName] == null)
{
messageDic.Remove(msgName);
}
}
}
// 触发消息
public static void TriggerEvent(string msgName, params object[] msg)
{
if (messageDic.TryGetValue(msgName, out EventHandler eventHandler))
{
eventHandler.Invoke(msg);
}
else
{
Debug.Log("消息" + msgName + "未注册");
}
}
// 清空所有消息监听
public static void Clear()
{
messageDic.Clear();
}
}
使用方法
先注册消息,开始监听事件。根据需求注销消息,取消监听事件。
cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class GameManager: MonoBehaviour
{
private void Start()
{
// 注册消息
EventCenter.AddListener("startGame", StartGame);
}
private void OnDestroy()
{
// 注销消息
EventCenter.RemoveListener("startGame", StartGame);
}
// 被监听的事件所对应的方法需要有一个与委托对应的参数类型 object[] args = null
public void StartGame(object[] args = null)
{
if (args != null)
{
foreach (var arg in args)
{
Debug.Log(arg);
}
}
Debug.Log("Start Game");
}
}
触发消息,触发监听事件。同时,下面设置了三个用例,在触发回调函数的同时还传回相关参数。
cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Test: MonoBehaviour
{
private void Update()
{
if (Input.GetKeyDown(KeyCode.J))
{
Test1();
}
if (Input.GetKeyDown(KeyCode.K))
{
Test2();
}
if (Input.GetKeyDown(KeyCode.L))
{
Test3();
}
}
void Test1()
{
// 触发消息
EventCenter.TriggerEvent("startGame");
}
void Test2()
{
// 触发消息
EventCenter.TriggerEvent("startGame", 1);
}
void Test3()
{
// 触发消息
EventCenter.TriggerEvent("startGame", 1, "test");
}
}
