Unity 事件中心
为了降低模块与模块之间的耦合,举个例子如下图
有 boss、player、winpanle(游戏胜利界面) ,当boss死亡时,玩家得到一定金币,游戏胜利面板弹出。通常的做法是在Boss脚本里 得到player 和 winpanle 的实例对象,然后再调用其对应函数
此做法简单,对于不复杂的业务逻辑比较友好也方便,但是对于稍微复杂点的业务逻辑就显得很混乱,模块间的耦合性也非常高 如图
这还只是4个模块间相互引用,更复杂的可能有几十个或上百,解决这问题就需要用到设计模式中的 发布订阅模式 (Publish–subscribe pattern) 。
boss把死亡消息发给中心(中间人Broker),此后就不用管了,谁需要这个事件 谁就订阅即可,中心会通知这些订阅者。玩家和胜利面板需要知道boss什么时候死亡,于是就订阅boss的死亡事件,boss死后就会收到通知。
UML关系图
脚本实现
创建IEventInfo接口和EventInfo类,类继承接口
using UnityEngine.Events;
interface IEventInfo { }
public class EventInfo<T> : IEventInfo {
public UnityAction<T> m_action;
public EventInfo (UnityAction<T> _action) {
m_action += _action;
}
}
事件中心实现 因为是唯一的 所以是单例 需继承单例基类
/// <summary>
/// 事件中心
/// </summary>
public class Evencenter : SingletonBase<Evencenter> {
private Dictionary<string, IEventInfo> m_eventDic;
protected override void Init () {
m_eventDic = new Dictionary<string, IEventInfo> ();
}
/// <summary>
/// 注册监听函数
/// </summary>
/// <param name="_eventName">事件名</param>
/// <param name="_action">回调函数</param>
/// <typeparam name="T">参数类型</typeparam>
public void AddEventListener<T> (string _eventName, UnityAction<T> _action) {
if (!m_eventDic.ContainsKey (_eventName)) {
m_eventDic.Add (_eventName, new EventInfo<T> (_action));
return;
}
(m_eventDic[_eventName] as EventInfo<T>).m_action += _action;
}
/// <summary>
/// 事件的发布
/// </summary>
/// <param name="_eventName">事件名</param>
/// <param name="_info">事件触发时需要传出去的参数</param>
/// <typeparam name="T">参数类型</typeparam>
public void EventTrigger<T> (string _eventName, T _info) {
if (m_eventDic.ContainsKey (_eventName) && (m_eventDic[_eventName] as EventInfo<T>).m_action != null)
(m_eventDic[_eventName] as EventInfo<T>).m_action (_info);//里氏转换 把父类转为子类
}
/// <summary>
/// 取消函数监听 一般用于对象销毁
/// </summary>
/// <param name="_eventName">事件名</param>
/// <param name="_action">注册的回调函数</param>
/// <typeparam name="T">参数类型</typeparam>
public void RemoveEventListener<T> (string _eventName, UnityAction<T> _action) {
(m_eventDic[_eventName] as EventInfo<T>).m_action -= _action;
}
public void Clear () {
m_eventDic.Clear ();
}
}
使用
分别创建boss、player、winpanle的GameObject和对应脚本
public class Boss : MonoBehaviour {
void Start () {
Invoke ("Die", 3);//延迟三秒Boss死亡
}
//死亡后发布死亡事件
void Die () {
// 回调函数的参数类型 事件名 回调函数参数 这里是boss名字
Evencenter.Instance.EventTrigger<string> ("BossDead", "加里奥");
}
}
public class Player : MonoBehaviour {
void Start () {
//对boss死亡这个事件进行监听
Evencenter.Instance.AddEventListener<string> ("BossDead", Fun);
}
void Fun (string _bossName) {
Debug.Log (_bossName + " 死亡 玩家加金币");
}
void OnDestroy () {
Evencenter.Instance.RemoveEventListener<string> ("BossDead", Fun);
}
}
public class WinPanle : MonoBehaviour {
void Start () {
Evencenter.Instance.AddEventListener<string> ("BossDead", (_bossName)=>{
Debug.Log (_bossName + " 死亡 胜利面板弹出");
});
}
}
点击运行按钮不出意外 3秒后 控制台会打印如下信息
最后
学习笔记,仅供参考,如有不正,欢迎指正