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);
    }
}
posted @ 2025-12-14 16:18  高山仰止666  阅读(31)  评论(0)    收藏  举报