Files
zeling_v2/Docs/DesignSpec/02_EventMessaging.md
2026-05-08 11:04:00 +08:00

7.4 KiB
Raw Permalink Blame History

02 · 事件与消息系统规范

所属文档集 ← 返回索引
摘要:定义游戏全局的事件通信规范、事件目录与发布/订阅契约。


目录

  1. 事件系统设计原则
  2. 事件类型体系
  3. 发布/订阅契约
  4. 全局事件目录
  5. 事件设计指导

1. 事件系统设计原则

原则 说明
最小载荷 事件只携带消费方需要的最少信息
类型安全 每个事件有明确的载荷类型,不使用无类型通用事件
无副作用传递 事件不携带可修改的对象引用,防止订阅方意外修改状态
单向通知 事件只通知"发生了什么",不携带"如何处理"的指令
有限生命周期 事件在发出后立即处理,不在系统间长期持有

2. 事件类型体系

2.1 按载荷分类

类型 描述 适用场景
Event<void> 无载荷事件,纯通知 玩家死亡、游戏暂停
Event<T> 单值载荷 HP 变化(传入新值)
Event<Payload> 结构体载荷 伤害事件(多字段)

2.2 按作用范围分类

类型 作用范围 说明
全局事件 全游戏有效,跨场景 玩家死亡、游戏暂停、存档完成
局部事件 单场景/房间内有效 敌人死亡、机关触发、Boss 阶段变更
实体事件 单个实体范围 单个 NPC 对话开始、单个陷阱激活

3. 发布/订阅契约

3.1 发布方契约

发布方Emitter必须

  • 在系统初始化时注册事件频道
  • 仅在状态确实发生变化时发出事件(不重复发出相同状态)
  • 在系统销毁时清理事件频道

3.2 订阅方契约

订阅方Listener必须

  • 在系统初始化时注册订阅
  • 在系统销毁时取消订阅(防止悬挂引用)
  • 不在事件处理中再发出同类型事件(防止递归循环)

3.3 事件处理顺序

当多个系统订阅同一事件时,处理顺序不保证
任何依赖特定顺序的逻辑应通过新增中间事件拆分为有序的因果链,而非依赖底层执行顺序。

❌ 错误:期望 A 先处理B 后处理同一事件
✅ 正确A 处理事件后发出新事件B 订阅新事件

4. 全局事件目录

4.1 玩家相关事件

事件名 载荷类型 发出方 典型订阅方 触发时机
OnPlayerDied void 玩家系统 UI、音频、存档、世界 玩家 HP 归零
OnPlayerRevived void 游戏管理器 玩家系统、UI、音频 复活流程完成
OnHPChanged {current: Integer, max: Integer} 玩家系统 UIHUD HP 任意变化
OnSoulPowerChanged {current: Integer, max: Integer} 玩家系统 UIHUD 灵力变化
OnSpiritPowerChanged {current: Integer, max: Integer} 玩家系统 UIHUD 魄元变化
OnSpringChargesChanged {current: Integer, max: Integer} 玩家系统 UIHUD 灵泉次数变化
OnGeoChanged {current: Integer, delta: Integer} 经济系统 UIHUD Geo 增减
OnAbilityUnlocked {abilityId: ID} 进程系统 玩家系统、UI 新能力获得
OnFormChanged {newFormId: ID} 形态系统 UI、音频、武器系统 玩家切换形态
OnParrySuccess {counterWindowDuration: Duration} 战斗系统 玩家系统、UI、音频 弹反判定成功
OnHitConfirmed HitPayload 战斗系统 玩家系统(灵力积累)、反馈系统 攻击命中判定

4.2 敌人相关事件

事件名 载荷类型 发出方 典型订阅方 触发时机
OnEnemyDied {enemyId: ID, position: Vector2} 敌人系统 进程系统、经济系统、叙事系统 敌人 HP 归零
OnEnemyHit HitPayload 战斗系统 反馈系统、音频 攻击命中敌人
OnBossPhaseChanged {bossId: ID, phase: Integer} Boss 系统 UI、音频 Boss 进入新阶段
OnBossDefeated {bossId: ID} 敌人系统 进程系统、叙事系统、存档 Boss 战胜利

4.3 世界/进程相关事件

事件名 载荷类型 发出方 典型订阅方 触发时机
OnSceneTransitionBegin {targetSceneId: ID} 世界系统 UI遮罩、输入系统 开始场景切换
OnSceneTransitionEnd {sceneId: ID} 世界系统 输入系统、音频 场景切换完成
OnSavePointActivated {savePointId: ID, position: Vector2} 世界系统 存档系统、玩家系统、UI 玩家激活存档点
OnRoomDiscovered {roomId: ID} 世界系统 地图系统 玩家首次进入房间
OnCollectiblePickedUp {collectibleId: ID, type: CollectibleType} 世界系统 进程系统、叙事系统 玩家拾取收集品
OnWorldFlagChanged {flagId: ID, value: Boolean} 叙事系统 叙事系统(自引用)、进程系统 世界状态标志变化

4.4 UI/系统相关事件

事件名 载荷类型 发出方 典型订阅方 触发时机
OnGamePaused void 游戏管理器 所有系统 暂停键触发
OnGameResumed void 游戏管理器 所有系统 恢复键触发
OnSaveCompleted {slotId: Integer} 存档系统 UI提示 存档写入完成
OnSettingsChanged SettingsPayload 设置系统 音频、无障碍、UI 等 设置项变更
OnAchievementUnlocked {achievementId: ID} 成就系统 UIToast 成就达成

5. 事件设计指导

5.1 新增事件时的决策流程

需要系统 A 通知系统 B 时:

  B 是否需要立即同步返回值?
  ├─ 是 → 使用接口调用(不是事件)
  └─ 否 → 使用事件

  事件是否跨多个系统关心?
  ├─ 是(多个系统订阅)→ 定义为全局事件,加入全局目录
  └─ 否(仅 A→B→ 考虑是否用接口更合适

  事件是否携带可变对象引用?
  ├─ 是 → 改为传递值类型载荷ID + 必要字段)
  └─ 否 → 可以使用

5.2 载荷设计规范

好的载荷(值类型,信息完整)

OnEnemyDied {
    enemyId  : ID       // 唯一标识,订阅方可用于查询更多信息
    position : Vector2  // 死亡位置(生成掉落物需要)
    lootTableId : ID    // 掉落表 ID经济系统直接使用
}

不好的载荷(引用传递,导致耦合)

OnEnemyDied {
    enemyRef : EnemyObject  // ❌ 引用具体对象,订阅方与敌人系统耦合
}

5.3 事件命名规范

规范 说明 示例
动词过去式On + 名词 + 动词过去式) 表示"已发生的事" OnPlayerDiedOnAbilityUnlocked
变化类用 Changed 状态数值变化 OnHPChangedOnGeoChanged
开始/结束对 持续性事件标注阶段 OnSceneTransitionBegin / OnSceneTransitionEnd
避免"Will/Should" 事件是通知,不是征询许可 OnPlayerWillDie OnPlayerDied