refactor(game): 移除已弃用的事件常量

- 删除 UpdateHero 和 UpdateFightHero 事件
- 移除 MISSION_UPDATE 事件常量
- 优化游戏事件枚举定义
This commit is contained in:
panw
2025-10-28 16:15:47 +08:00
parent b765e6a7a6
commit 4235e3b776
74 changed files with 31775 additions and 3 deletions

View File

@@ -0,0 +1,262 @@
# 事件系统
<cite>
**本文档引用文件**
- [GameEvent.ts](file://assets/script/game/common/config/GameEvent.ts)
- [event.md](file://doc/core/common/event.md)
- [MessageManager.ts](file://extensions/oops-plugin-framework/assets/core/common/event/MessageManager.ts)
- [SingletonModuleComp.ts](file://assets/script/game/common/SingletonModuleComp.ts)
- [TopComp.ts](file://assets/script/game/map/TopComp.ts)
- [MInfoComp.ts](file://assets/script/game/map/MInfoComp.ts)
- [move.ts](file://assets/script/game/map/move.ts)
- [TalComp.ts](file://assets/script/game/hero/TalComp.ts)
</cite>
## 目录
1. [事件常量分类与业务含义](#事件常量分类与业务含义)
2. [事件监听机制与内存管理](#事件监听机制与内存管理)
3. [事件系统解耦设计与应用示例](#事件系统解耦设计与应用示例)
4. [事件命名规范与作用域管理](#事件命名规范与作用域管理)
5. [事件调试与常见问题解决方案](#事件调试与常见问题解决方案)
## 事件常量分类与业务含义
基于 `GameEvent.ts` 枚举文件,游戏全局事件按功能模块可分为以下几类:
### 战斗流程事件
- `MissionStart`:关卡开始时触发,初始化战斗环境
- `MissionWin`:玩家胜利时触发,进入结算流程
- `MissionLoss`:玩家失败时触发,显示失败界面
- `FightStart`:战斗正式开始,激活战斗逻辑
- `FightEnd`:战斗结束,无论胜负均触发
- `NewWave`:新一波敌人出现,用于刷新怪物生成
### 英雄相关事件
- `HeroLvUp`英雄升级时触发用于属性更新和UI反馈
- `HeroUnlock`新英雄解锁时触发通知UI展示获取动画
- `HeroDead`:英雄死亡时触发,处理死亡逻辑和成就判断
- `HeroSelect`:选择出战英雄时触发,更新队伍配置
- `HeroSkillSelect`:技能选择阶段触发,激活技能选择界面
### 资源更新事件
- `GOLD_UPDATE`金币数量变化时触发用于UI金币显示更新
- `DIAMOND_UPDATE`:钻石数量变化时触发
- `MEAT_UPDATE`:游戏内特定资源"肉"的数量更新
- `MISSION_UPDATE`关卡进度更新用于顶部UI显示当前关卡
### 界面与交互事件
- `ShopOpen`:商店界面打开时触发
- `HerosOpen`:英雄列表界面打开
- `RestOpen`:休息界面打开
- `HeroInfoOpen`:英雄详情界面打开
- `GuideStart``GuideEnd`:新手引导流程控制
### 地图移动事件
- `MAP_MOVE_END_LEFT`:地图向左移动到达边界
- `MAP_MOVE_END_RIGHT`:地图向右移动到达边界
- `CardsClose`:卡牌选择界面关闭
### 卡牌与技能事件
- `CardRefresh`:卡牌刷新时触发
- `UseHeroCard`:使用英雄卡牌
- `UseSkillCard`:使用技能卡牌
- `UseTalentCard`:使用天赋卡牌
- `CastSkill`:技能施放
**Section sources**
- [GameEvent.ts](file://assets/script/game/common/config/GameEvent.ts)
## 事件监听机制与内存管理
### 持续监听与单次监听的差异
`oops.message.on()` 用于注册持续监听的事件,监听器会一直存在直到显式移除。适用于需要长期响应的事件,如资源更新、状态变化等。
```typescript
oops.message.on(GameEvent.GOLD_UPDATE, this.onGoldUpdate, this);
```
`oops.message.once()` 用于注册只触发一次的事件监听,事件响应后监听器自动移除。适用于一次性流程,如初始化完成、首次加载等场景。
```typescript
oops.message.once(GameEvent.GameServerConnected, this.onHandler, this);
```
`MessageManager.ts` 的实现可以看出,`once()` 方法通过创建一个包装函数 `_listener`,在事件触发后立即调用 `off()` 移除自身,确保只执行一次。
### 内存泄漏防范措施
为防止内存泄漏,必须在对象销毁时移除所有事件监听。通常在 `onDestroy()``reset()` 生命周期方法中执行:
```typescript
protected onDestroy() {
oops.message.off(GameEvent.GOLD_UPDATE, this.onGoldUpdate, this);
}
```
`MessageManager` 在注册事件时会检查重复注册,并发出警告,避免同一对象对同一事件的重复监听。
**Section sources**
- [event.md](file://doc/core/common/event.md)
- [MessageManager.ts](file://extensions/oops-plugin-framework/assets/core/common/event/MessageManager.ts)
## 事件系统解耦设计与应用示例
### 解耦模块间通信
事件系统通过发布-订阅模式实现模块间的松耦合通信。发送方无需知道接收方的存在,接收方也无需主动轮询状态变化。
#### 英雄升级事件HeroLvUp的完整流程
1. **事件触发**:当英雄经验值满足升级条件时,触发 `HeroLvUp` 事件
2. **UI更新**UI组件监听 `HeroLvUp` 事件,更新英雄等级显示和属性面板
3. **成就判断**:成就系统监听该事件,判断是否达成"快速升级"等成就条件
4. **天赋系统响应**:某些天赋(如"每升5级攻击力+10%")在等级变化时触发效果
#### 金币更新事件的实际应用
`SingletonModuleComp.ts` 中,当金币数量变化时触发 `GOLD_UPDATE` 事件:
```typescript
updateGold(gold: number) {
this.vmdata.gold += gold;
// ... 更新云端数据
oops.message.dispatchEvent(GameEvent.GOLD_UPDATE);
}
```
`TopComp.ts`顶部UI组件监听该事件并执行视觉反馈
```typescript
onGoldUpdate(event: string, data: any) {
tween(this.node.getChildByName("bar").getChildByName("gold").getChildByName("num").getComponent(Label).node)
.to(0.1, { scale: v3(1.2, 1.2, 1) })
.to(0.1, { scale: v3(1, 1, 1) })
.start();
}
```
这种设计使得金币逻辑与UI展示完全分离任何模块都可以独立修改而不影响其他部分。
### 地图移动事件的循环机制
`move.ts` 文件展示了 `MAP_MOVE_END_LEFT``MAP_MOVE_END_RIGHT` 事件的闭环设计:
1. 地图移动组件监听边界到达事件
2. 当到达边界时,重置位置并派发对应的边界事件
3. 其他组件可以监听这些事件执行相应逻辑
```mermaid
flowchart TD
A[地图移动] --> B{到达右边界?}
B --> |是| C[重置到左边界]
C --> D[派发MAP_MOVE_END_LEFT]
D --> E[其他组件响应]
B --> |否| F{到达左边界?}
F --> |是| G[重置到右边界]
G --> H[派发MAP_MOVE_END_RIGHT]
H --> I[其他组件响应]
```
**Diagram sources**
- [SingletonModuleComp.ts](file://assets/script/game/common/SingletonModuleComp.ts)
- [TopComp.ts](file://assets/script/game/map/TopComp.ts)
- [move.ts](file://assets/script/game/map/move.ts)
**Section sources**
- [SingletonModuleComp.ts](file://assets/script/game/common/SingletonModuleComp.ts)
- [TopComp.ts](file://assets/script/game/map/TopComp.ts)
- [MInfoComp.ts](file://assets/script/game/map/MInfoComp.ts)
- [move.ts](file://assets/script/game/map/move.ts)
## 事件命名规范与作用域管理
### 命名规范
事件名称采用大写常量格式,使用有意义的描述性名称。遵循以下原则:
- 使用名词或名词短语,如 `GOLD_UPDATE``HeroLvUp`
- 模块相关事件添加前缀,如 `MAP_MOVE_END_LEFT`
- 业务流程事件使用动词,如 `MissionWin``FightStart`
- 避免缩写,确保名称清晰可读
### 作用域管理
事件系统通过第三个参数 `this` 管理作用域,确保回调函数在正确的上下文中执行。这解决了 JavaScript/TypeScript 中常见的 `this` 上下文丢失问题。
在注册事件时,必须传入正确的对象引用,以便在移除监听时能够精确匹配。
```typescript
oops.message.on(GameEvent.GOLD_UPDATE, this.onGoldUpdate, this);
```
这里的 `this` 确保了:
1. 回调函数在正确的对象实例上下文中执行
2. 移除监听时能够准确找到对应的监听器
3. 避免不同实例间的监听器混淆
**Section sources**
- [MessageManager.ts](file://extensions/oops-plugin-framework/assets/core/common/event/MessageManager.ts)
## 事件调试与常见问题解决方案
### 调试技巧
#### 事件监听器dump
可以通过访问 `MessageManager` 的内部 `events` 对象来查看当前所有注册的事件监听器,便于调试和性能分析。
#### 事件触发跟踪
在开发环境中,可以临时修改 `dispatchEvent` 方法,添加日志输出,跟踪所有事件的触发情况。
```mermaid
flowchart LR
A[事件注册] --> B[事件派发]
B --> C{是否有监听器?}
C --> |是| D[执行所有监听器]
D --> E[回调函数执行]
C --> |否| F[无操作]
```
### 常见问题及解决方案
#### 事件重复注册
**问题**:同一对象对同一事件多次注册,导致回调执行多次。
**解决方案**
1.`onLoad()` 中注册事件,在 `onDestroy()` 中移除
2. 使用 `MessageManager` 的重复注册警告功能及时发现
3. 在复杂场景下,使用标志位确保只注册一次
#### this上下文丢失
**问题**:回调函数中的 `this` 指向错误的对象。
**解决方案**
1. 严格按照 `oops.message.on(event, handler, this)` 格式注册
2. 避免使用箭头函数作为回调,除非明确不需要绑定作用域
3. 在 TypeScript 中利用类型检查确保第三个参数正确
#### 内存泄漏
**问题**:对象销毁后事件监听器未移除,导致对象无法被垃圾回收。
**解决方案**
1. 严格遵守生命周期,在 `onDestroy()` 中调用 `off()`
2. 对于临时组件,使用 `once()` 替代 `on()`
3. 使用事件管理器批量管理事件的注册和移除
#### 事件命名冲突
**问题**:不同模块使用相同名称的事件导致意外行为。
**解决方案**
1. 使用模块前缀,如 `MAP_``HERO_`
2.`GameEvent` 枚举中统一管理所有事件名称
3. 避免使用过于通用的名称
**Section sources**
- [MessageManager.ts](file://extensions/oops-plugin-framework/assets/core/common/event/MessageManager.ts)
- [TalComp.ts](file://assets/script/game/hero/TalComp.ts)