406 字
2 分钟
游戏设计模式03——极简事件中心
TIP

本方法适用于小型项目。核心思路是一个事件对应一个 static event 字段,再配一个触发方法,不用字典,也不用字符串当 key。

核心代码#

using System;
using UnityEngine;
public static class EventCenter
{
// 无参事件
public static event Action OnSelect;
public static void RaiseSelect() => OnSelect?.Invoke();
// 带参事件
public static event Action<int> OnScoreChanged;
public static void RaiseScoreChanged(int score) => OnScoreChanged?.Invoke(score);
// 进入 Play 模式时清空,防止关闭 Domain Reload 后残留旧订阅
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)]
private static void ResetAll()
{
OnSelect = null;
OnScoreChanged = null;
}
}

外部订阅/触发方式#

订阅方#

public class SelectUI : MonoBehaviour
{
private void OnEnable() => EventCenter.OnSelect += HandleSelect;
private void OnDisable() => EventCenter.OnSelect -= HandleSelect;
private void HandleSelect()
{
Debug.Log("选中了");
}
}

触发方#

EventCenter.RaiseSelect();
EventCenter.RaiseScoreChanged(100);

优点#

  • 简单直观:一个事件就是一个字段加一个方法。
  • 类型安全:拼错字名字会直接编译报错。
  • 好追踪:在 IDE 里对事件”查找所有引用”,就能看到所有订阅方和触发方。
  • 几乎零开销: 没有字典查找,没有类型转换,也没有 GC。
  • event 关键字能保护订阅: 外部只能 += 和 -=,不能直接调用事件,也不能写 = null 清掉别人的订阅。所以需要用 RaiseXxx() 来触发。

注意事项#

  • 成对取消订阅(最重要): 订阅写在 OnEnable,取消写在 OnDisable。静态事件会一直持有订阅对象的引用,不取消就会内存泄漏,或者报 MissingReferenceException。
  • 不要用 Lambda 订阅: OnSelect += () => {…} 之后没法取消,应该用方法名。
  • Domain Reload: 关闭 Domain Reload 后,静态事件会保留上次运行的订阅,所以要在 ResetAll() 里清空。