事件分发器:一对多广播

接口解决"一对一解耦",事件分发器(Event Dispatcher)解决"一对多"。

经典场景:Boss 死亡。要通知 UI 切画面、通知小怪逃跑、通知任务系统计数、通知全体玩家。如果 Boss 逐一 Cast 调用,代码里就写死了四个接收者,以后加第五个还得改 Boss。

蓝图用法

  1. 在 Boss 蓝图的 My Blueprint 面板新建 Event Dispatcher,如 OnBossDied;
  2. 别的蓝图通过 Bind Event to OnBossDied 节点订阅(输入 Boss 引用);
  3. Boss 死亡时调用 Call OnBossDied——所有订阅者同时收到。
Boss 蓝图
  └─ Call OnBossDied ──┬──> UI 蓝图(播结算)
                       ├──> 小怪 AI(进入逃跑)
                       ├──> 任务系统(+1 计数)
                       └──> 玩家控制器(成就)

关键优势:Boss 完全不知道有谁订阅,新增订阅者不用动 Boss 一根线。

C++ 侧:委托

C++ 里同样效果用委托(Delegate)实现。蓝图里的事件分发器,本质就是暴露给蓝图的 C++ 委托:

// 声明(类里)
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnBossDied, AActor*, Boss);

public:
    UPROPERTY(BlueprintAssignable, Category="Boss")
    FOnBossDied OnBossDied;

BlueprintAssignable 让蓝图能绑定事件;C++ 里用 OnBossDied.Broadcast(Boss) 广播。这就是"跨层事件"的标准做法:C++ 负责广播,蓝图负责订阅与表现。

委托的三种形态

类型 C++ 宏 谁能订阅 何时清理
普通委托 DECLARE_DELEGATE 只 C++ 手动
多播委托 DECLARE_MULTICAST_DELEGATE 只 C++(多个) 手动
动态多播 DECLARE_DYNAMIC_MULTICAST... C++ + 蓝图 蓝图绑定自动随对象销毁清理

给蓝图用的事件一律 DYNAMIC_MULTICAST + BlueprintAssignable。参数用 OneParam/TwoParams/ThreeParam 后缀,蓝图里就能直接取到参数。

广播的生命周期注意

  • 广播时若某个订阅者已被销毁 → 动态委托会自动跳过(安全),普通委托需要自己确保;
  • Broadcast 的顺序不是调用者能依赖的——不要写"依赖订阅顺序"的逻辑;
  • 广播在 C++ 里执行,订阅回调可能进入蓝图 VM——同.hot path 限制(别每帧广播给几百个蓝图订阅者)。

本章小结

  • 事件分发器 = 一对多广播:发布者不认识订阅者。
  • 蓝图事件分发器底层就是 DECLARE_DYNAMIC_MULTICAST_DELEGATE + BlueprintAssignable。
  • 跨"系统→表现"的事件流(Boss 死亡、物品拾取、任务完成)都该用广播,而非互相 Cast。