事件系统

Fink Framework 内置一套 轻量级、强类型、无 GC 的全局事件系统,用于模块间解耦通信。 你可以通过事件实现:

  • UI → 逻辑通信
  • 场景加载进度同步
  • 输入事件广播
  • 数据变化通知
  • 任意模块间的松耦合消息分发

1. 添加事件类型

所有事件都必须在 E_EventType.cs 中声明。

路径: Framework/Event/E_EventType.cs

示例:

/// <summary>
/// 测试事件 —— 无参数
/// </summary>
E_Test,

/// <summary>
/// 场景加载进度 —— float
/// </summary>
E_SceneLoadChange

如果你不在这里声明事件,事件系统将无法识别该事件类型!

事件最好按模块分类,如:

#region UI
UI_Open,
UI_Close,
#endregion

#region Scene
Scene_LoadChange,
Scene_Loaded,
#endregion

2. 核心结构

EventManager         // 全局事件中心(单例)
EventInfo            // 无参事件容器
EventInfo<T>         // 单参数事件容器
EventInfo<T1,T2>     // 双参数事件容器
E_EventType          // 全局枚举事件类型

3. 注册事件监听

3.1 无参事件

示例:

EventManager.Instance.AddEventListener(E_EventType.E_Test, OnTest);
// 回调函数
void OnTest()
{
    Debug.Log("Test Event Triggered");
}

3.2 单参数事件

示例:

EventManager.Instance.AddEventListener<float>(E_EventType.E_SceneLoadChange, OnProgress);
// 回调函数
void OnProgress(float value)
{
    Debug.Log("Progress = " + value);
}

3.3 双参数事件

示例:

EventManager.Instance.AddEventListener<float, float>(E_EventType.E_Loading, OnLoadStep);
// 回调函数
void OnLoadStep(float cur, float total)
{
    Debug.Log($"{cur}/{total}");
}

4. 触发事件

4.1 无参触发

示例:

EventManager.Instance.EventTrigger(E_EventType.E_Test);

4.2 单参触发

示例:

EventManager.Instance.EventTrigger<float>(E_EventType.E_SceneLoadChange, 0.5f);

4.3 双参触发

示例:

EventManager.Instance.EventTrigger<float, float>(E_EventType.E_Loading, 20, 100);

5. 移除监听(必须)

如果你在 OnEnable 注册事件,必须在 OnDisable 移除:

示例:

EventManager.Instance.RemoveEventListener(E_EventType.E_Test, OnTest);\

防止内存泄漏和重复监听。


6. 清理事件(切换场景时推荐)

若您使用框架内置的场景切换系统来加载场景,则已经内置了在切换场景时清除事件监听的逻辑。 详情请见场景切换系统

EventManager.Instance.ClearAllEvent();

或只清理某一类事件:

EventManager.Instance.ClearEvent(E_EventType.E_Test);

7. 粘性事件(Sticky Event)

粘性事件的特性:

事件触发后,新加入的监听者也会立刻收到最近一次的值。

注册方式:

EventManager.Instance.AddEventListener<float>(E_EventType.E_SceneLoadChange, OnProgress, sticky: true);

适合:

  • 场景加载进度
  • 配置初始化状态
  • 玩家数据准备完成

不适合:

  • 高频 Tick
  • 输入事件
  • 每帧更新事件

8. 事件自动绑定工具(强烈推荐)

为了避免手动移除监听带来的重复绑定、忘记解绑、切场景残留等问题, Fink Framework 提供了 EventAutoBinder —— 一行代码即可实现事件的自动注册与自动解绑。

EventAutoBinder 支持两种工作模式:

  • Bind() —— 立即注册,并在 OnDestroy 自动解绑(适合逻辑类、常驻对象)

  • BindAuto() —— OnEnable 自动注册,OnDisable 自动解绑(适合 UI 面板、临时对象)

7.1 Bind() 默认模式

用法:

EventAutoBinder.Bind(this, E_EventType.UI_Open, OnOpen);

等价于:

AddEventListener(...)    // 立即注册
OnDestroy -> RemoveEventListener(...)  // 自动解绑

示例:

private void Start()
{
    EventAutoBinder.Bind(this, E_EventType.UI_Open, OnOpen);
}

void OnOpen()
{
    Debug.Log("UI Open Event Received");
}

7.2 BindAuto() 自动模式

用法:

EventAutoBinder.BindAuto(this, E_EventType.E_SceneLoadChange, OnProgress);

等价于:

OnEnable  -> AddEventListener(...)
OnDisable -> RemoveEventListener(...)

示例:

private void OnEnable()
{
    EventAutoBinder.BindAuto(this, E_EventType.E_SceneLoadChange, OnProgress);
}

void OnProgress(float p)
{
    Debug.Log("Loading: " + p);
}

你无需再写 OnDisable 代码,自动解绑会帮你做干净。

7.3 支持 0 / 1 / 2 参数事件

EventAutoBinder 完全支持:

Bind(type, UnityAction)
Bind<T>(type, UnityAction<T>)
Bind<T1,T2>(type, UnityAction<T1,T2>)

以及对应的 BindAuto 版本。

示例:

EventAutoBinder.BindAuto<float, float>(this, E_EventType.E_Loading, OnStep);

void OnStep(float cur, float total)
{
    Debug.Log($"{cur}/{total}");
}