chore: initial commit
This commit is contained in:
173
Docs/DesignSpec/02_EventMessaging.md
Normal file
173
Docs/DesignSpec/02_EventMessaging.md
Normal file
@@ -0,0 +1,173 @@
|
||||
# 02 · 事件与消息系统规范
|
||||
|
||||
> **所属文档集** [← 返回索引](./README.md)
|
||||
> **摘要**:定义游戏全局的事件通信规范、事件目录与发布/订阅契约。
|
||||
|
||||
---
|
||||
|
||||
## 目录
|
||||
|
||||
1. [事件系统设计原则](#1-事件系统设计原则)
|
||||
2. [事件类型体系](#2-事件类型体系)
|
||||
3. [发布/订阅契约](#3-发布订阅契约)
|
||||
4. [全局事件目录](#4-全局事件目录)
|
||||
5. [事件设计指导](#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}` | 玩家系统 | UI(HUD)| HP 任意变化 |
|
||||
| `OnSoulPowerChanged` | `{current: Integer, max: Integer}` | 玩家系统 | UI(HUD)| 灵力变化 |
|
||||
| `OnSpiritPowerChanged` | `{current: Integer, max: Integer}` | 玩家系统 | UI(HUD)| 魄元变化 |
|
||||
| `OnSpringChargesChanged` | `{current: Integer, max: Integer}` | 玩家系统 | UI(HUD)| 灵泉次数变化 |
|
||||
| `OnGeoChanged` | `{current: Integer, delta: Integer}` | 经济系统 | UI(HUD)| 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}` | 成就系统 | UI(Toast)| 成就达成 |
|
||||
|
||||
---
|
||||
|
||||
## 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 + 名词 + 动词过去式)| 表示"已发生的事" | `OnPlayerDied`、`OnAbilityUnlocked` |
|
||||
| 变化类用 Changed | 状态数值变化 | `OnHPChanged`、`OnGeoChanged` |
|
||||
| 开始/结束对 | 持续性事件标注阶段 | `OnSceneTransitionBegin` / `OnSceneTransitionEnd` |
|
||||
| 避免"Will/Should" | 事件是通知,不是征询许可 | ❌ `OnPlayerWillDie`,✅ `OnPlayerDied` |
|
||||
Reference in New Issue
Block a user