# 技能执行资源管理 **本文档中引用的文件** - [SkillConComp.ts](file://assets/script/game/hero/SkillConComp.ts) - [SkillEnt.ts](file://assets/script/game/skill/SkillEnt.ts) - [GameEvent.ts](file://assets/script/game/common/config/GameEvent.ts) - [MissionComp.ts](file://assets/script/game/map/MissionComp.ts) - [HeroViewComp.ts](file://assets/script/game/hero/HeroViewComp.ts) - [HeroConComp.ts](file://assets/script/game/hero/HeroConComp.ts) - [timer.md](file://doc/core/common/timer.md) - [MapView.ts](file://assets/script/game/map/MapView.ts) ## 目录 1. [引言](#引言) 2. [项目结构概述](#项目结构概述) 3. [核心组件分析](#核心组件分析) 4. [架构概览](#架构概览) 5. [详细组件分析](#详细组件分析) 6. [依赖关系分析](#依赖关系分析) 7. [性能考量](#性能考量) 8. [故障排除指南](#故障排除指南) 9. [结论](#结论) ## 引言 在Cocos游戏引擎的战斗系统中,技能执行过程中的定时器资源管理是一个关键的系统级问题。本文档深入分析了技能执行过程中定时器资源的创建、存储、清理和生命周期管理策略,重点关注`_doSkill`方法中`setTimeout`创建的timerId如何被存储于`_timers`对象中,并通过`clear_timer`方法统一清除的完整流程。 ## 项目结构概述 该项目采用基于组件的架构设计,技能系统的核心组件分布在以下目录结构中: ```mermaid graph TB subgraph "技能系统架构" SkillConComp["SkillConComp
技能控制器组件"] SkillEnt["SkillEnt
技能实体管理"] HeroViewComp["HeroViewComp
英雄视图组件"] MissionComp["MissionComp
任务管理组件"] end subgraph "事件系统" GameEvent["GameEvent
游戏事件枚举"] MessageSystem["消息系统
事件分发"] end subgraph "定时器管理" TimerModule["定时器模块
Oops Framework"] LocalTimers["_timers对象
本地定时器存储"] end SkillConComp --> SkillEnt SkillConComp --> HeroViewComp MissionComp --> GameEvent GameEvent --> MessageSystem SkillConComp --> LocalTimers TimerModule --> LocalTimers ``` **图表来源** - [SkillConComp.ts](file://assets/script/game/hero/SkillConComp.ts#L1-L177) - [SkillEnt.ts](file://assets/script/game/skill/SkillEnt.ts#L1-L78) - [GameEvent.ts](file://assets/script/game/common/config/GameEvent.ts#L1-L70) **章节来源** - [SkillConComp.ts](file://assets/script/game/hero/SkillConComp.ts#L1-L50) - [SkillEnt.ts](file://assets/script/game/skill/SkillEnt.ts#L1-L30) ## 核心组件分析 ### SkillConComp - 技能控制器组件 `SkillConComp`是技能系统的核心控制器,负责技能的施放、定时器管理和生命周期控制。该组件维护了一个私有的`_timers`对象,用于存储所有技能执行过程中创建的定时器ID。 #### 主要特性: - **定时器存储管理**:使用`_timers: { [key: string]: any } = {}`对象存储定时器 - **生命周期钩子**:实现了`onDestroy`和`reset`方法进行资源清理 - **事件监听**:订阅`FightEnd`事件进行自动清理 - **节点有效性检查**:在多个关键点进行节点有效性验证 #### 定时器管理流程: ```mermaid sequenceDiagram participant Player as "玩家输入" participant SkillCon as "SkillConComp" participant Timer as "setTimeout" participant TimersObj as "_timers对象" participant EventSys as "事件系统" participant Cleanup as "清理机制" Player->>SkillCon : castSkill() SkillCon->>SkillCon : doSkill() SkillCon->>Timer : setTimeout(callback, delay) Timer-->>SkillCon : timerId SkillCon->>TimersObj : this._timers[key] = timerId Note over SkillCon,TimersObj : 定时器创建完成 alt 战斗结束事件触发 EventSys->>SkillCon : FightEnd事件 SkillCon->>Cleanup : clear_timer() Cleanup->>TimersObj : Object.values(_timers).forEach(clearTimeout) TimersObj-->>Cleanup : 清理所有定时器 else 组件销毁 SkillCon->>Cleanup : onDestroy() Cleanup->>TimersObj : Object.values(_timers).forEach(clearTimeout) Cleanup->>TimersObj : this._timers = {} end ``` **图表来源** - [SkillConComp.ts](file://assets/script/game/hero/SkillConComp.ts#L66-L110) - [SkillConComp.ts](file://assets/script/game/hero/SkillConComp.ts#L150-L177) **章节来源** - [SkillConComp.ts](file://assets/script/game/hero/SkillConComp.ts#L18-L35) - [SkillConComp.ts](file://assets/script/game/hero/SkillConComp.ts#L66-L110) ## 架构概览 技能执行资源管理系统采用多层次的清理策略,确保定时器资源得到妥善管理: ```mermaid flowchart TD Start([技能施放开始]) --> ValidateNode["节点有效性检查"] ValidateNode --> CreateTimer["创建setTimeout定时器"] CreateTimer --> StoreTimer["存储到_timers对象"] StoreTimer --> ExecuteSkill["执行技能逻辑"] ExecuteSkill --> CheckEvent{"战斗结束事件?"} CheckEvent --> |是| AutoCleanup["自动清理机制"] CheckEvent --> |否| ContinueExecution["继续执行"] ContinueExecution --> CheckDestroy{"组件销毁?"} CheckDestroy --> |是| ManualCleanup["手动清理机制"] CheckDestroy --> |否| WaitNextFrame["等待下一帧"] AutoCleanup --> ClearAllTimers["clear_timer()清理所有定时器"] ManualCleanup --> ClearAllTimers ClearAllTimers --> ResetTimersObj["重置_timers对象"] ResetTimersObj --> RemoveListeners["移除事件监听器"] WaitNextFrame --> CheckEvent RemoveListeners --> End([资源清理完成]) ``` **图表来源** - [SkillConComp.ts](file://assets/script/game/hero/SkillConComp.ts#L150-L177) - [MissionComp.ts](file://assets/script/game/map/MissionComp.ts#L80-L95) ## 详细组件分析 ### 定时器创建与存储机制 #### doSkill方法中的定时器创建 在`doSkill`方法中,技能执行采用了延迟执行模式,通过`setTimeout`创建定时器来延迟技能的实际执行: ```mermaid classDiagram class SkillConComp { -_timers : { [key : string] : any } +doSkill(config, is_wfuny, dmg) +clear_timer() +onDestroy() +reset() } class TimerStorage { +storeTimer(key, timerId) +clearAllTimers() +resetObject() } class NodeValidation { +checkNodeValidity() +checkHeroViewValidity() } SkillConComp --> TimerStorage : "管理" SkillConComp --> NodeValidation : "验证" TimerStorage --> NodeValidation : "依赖" ``` **图表来源** - [SkillConComp.ts](file://assets/script/game/hero/SkillConComp.ts#L66-L110) #### 定时器存储策略 定时器ID通过键值对形式存储在`_timers`对象中,键名采用`skill_{uuid}`格式,确保唯一性和可追溯性: | 存储策略 | 优势 | 应用场景 | |---------|------|----------| | 键值对存储 | 支持按技能UUID快速查找和清理 | 单个技能的精确清理 | | 对象引用 | 集合操作支持批量清理 | 批量资源清理 | | 类型安全 | TypeScript类型约束 | 编译时错误预防 | **章节来源** - [SkillConComp.ts](file://assets/script/game/hero/SkillConComp.ts#L66-L110) ### 生命周期钩子中的定时器清理 #### onDestroy方法的清理策略 `onDestroy`方法实现了组件销毁时的资源清理,这是防止内存泄漏的最后一道防线: ```mermaid flowchart LR OnDestroy[onDestroy触发] --> ClearTimers["Object.values(_timers).forEach(clearTimeout)"] ClearTimers --> ResetObject["this._timers = {}"] ResetObject --> RemoveListeners["this.off(GameEvent.CastHeroSkill)"] RemoveListeners --> Complete[清理完成] subgraph "清理保护机制" SafetyCheck["节点有效性检查"] NullCheck["空值检查"] TypeGuard["类型守卫"] end ClearTimers -.-> SafetyCheck ClearTimers -.-> NullCheck ClearTimers -.-> TypeGuard ``` **图表来源** - [SkillConComp.ts](file://assets/script/game/hero/SkillConComp.ts#L150-L177) #### reset方法的资源重置 `reset`方法提供了组件重置时的资源清理功能,主要用于组件池化场景: | 清理阶段 | 操作内容 | 目的 | |---------|----------|------| | 定时器清理 | 调用`clear_timer()`方法 | 防止定时器残留 | | 状态重置 | 重置内部状态变量 | 准备组件复用 | | 事件解绑 | 解除事件监听器 | 避免内存泄漏 | **章节来源** - [SkillConComp.ts](file://assets/script/game/hero/SkillConComp.ts#L140-L150) ### FightEnd事件监听机制 #### 战斗结束自动清理触发路径 战斗结束时的自动清理通过事件驱动机制实现,确保所有技能定时器得到及时清理: ```mermaid sequenceDiagram participant Hero as "英雄死亡" participant MissionComp as "MissionComp" participant MessageSys as "消息系统" participant SkillCon as "SkillConComp" participant TimerMgr as "定时器管理器" Hero->>MissionComp : do_hero_dead() MissionComp->>MissionComp : 检查英雄数量 alt 英雄全部死亡 MissionComp->>MessageSys : dispatchEvent(FightEnd) MessageSys->>SkillCon : 触发FightEnd事件 SkillCon->>TimerMgr : clear_timer() TimerMgr->>TimerMgr : 清理所有定时器 end ``` **图表来源** - [MissionComp.ts](file://assets/script/game/map/MissionComp.ts#L55-L65) - [SkillConComp.ts](file://assets/script/game/hero/SkillConComp.ts#L20-L25) #### 事件监听器的注册与管理 `init`方法中注册了`FightEnd`事件监听器,确保战斗结束时能够触发自动清理: | 监听器类型 | 事件名称 | 回调函数 | 清理时机 | |-----------|----------|----------|----------| | 单次监听 | FightEnd | clear_timer | 战斗结束时 | | 生命周期监听 | onDestroy | 清理所有定时器 | 组件销毁时 | | 事件解绑 | CastHeroSkill | 移除特定事件监听 | 组件销毁时 | **章节来源** - [SkillConComp.ts](file://assets/script/game/hero/SkillConComp.ts#L20-L25) - [MissionComp.ts](file://assets/script/game/map/MissionComp.ts#L55-L65) ### 异常场景下的安全性检查 #### 节点有效性检查实践 在技能执行的关键路径上,实施了多层节点有效性检查,防止因节点被提前销毁而导致的异常: ```mermaid flowchart TD EnterMethod[进入方法] --> FirstCheck["首次节点检查"] FirstCheck --> IsValid1{"节点有效?"} IsValid1 --> |否| EarlyReturn["提前返回"] IsValid1 --> |是| ExecuteLogic["执行业务逻辑"] ExecuteLogic --> SecondCheck["二次节点检查"] SecondCheck --> IsValid2{"节点仍然有效?"} IsValid2 --> |否| SafeExit["安全退出"] IsValid2 --> |是| ContinueExecution["继续执行"] ContinueExecution --> ThirdCheck["英雄视图检查"] ThirdCheck --> IsValid3{"英雄视图有效?"} IsValid3 --> |否| GracefulFail["优雅失败"] IsValid3 --> |是| FinalExecution["最终执行"] EarlyReturn --> End[方法结束] SafeExit --> End GracefulFail --> End FinalExecution --> End ``` **图表来源** - [SkillConComp.ts](file://assets/script/game/hero/SkillConComp.ts#L70-L75) - [SkillConComp.ts](file://assets/script/game/hero/SkillConComp.ts#L80-L85) #### 异常处理策略 | 异常类型 | 检查点 | 处理策略 | 预防措施 | |---------|--------|----------|----------| | 节点被销毁 | 每次关键操作前 | 提前返回,避免操作 | 定期检查节点有效性 | | 英雄视图丢失 | 技能执行前 | 日志记录,跳过执行 | 保持对英雄状态的监控 | | 定时器失效 | 定时器回调中 | 检查上下文有效性 | 使用闭包保护上下文 | **章节来源** - [SkillConComp.ts](file://assets/script/game/hero/SkillConComp.ts#L70-L75) - [SkillConComp.ts](file://assets/script/game/hero/SkillConComp.ts#L80-L85) ## 依赖关系分析 ### 组件间依赖关系 技能执行资源管理系统涉及多个组件间的复杂依赖关系: ```mermaid graph TB subgraph "核心组件" SkillConComp["SkillConComp
技能控制器"] SkillEnt["SkillEnt
技能实体"] HeroViewComp["HeroViewComp
英雄视图"] end subgraph "事件系统" GameEvent["GameEvent
事件枚举"] MessageSystem["消息系统"] end subgraph "资源管理" TimerModule["定时器模块"] ComponentPool["组件池"] end subgraph "战斗系统" MissionComp["MissionComp
任务管理"] BattleManager["战斗管理器"] end SkillConComp --> SkillEnt SkillConComp --> HeroViewComp SkillConComp --> TimerModule SkillConComp --> GameEvent GameEvent --> MessageSystem MessageSystem --> SkillConComp MissionComp --> BattleManager BattleManager --> MessageSystem SkillConComp -.-> ComponentPool HeroViewComp -.-> ComponentPool ``` **图表来源** - [SkillConComp.ts](file://assets/script/game/hero/SkillConComp.ts#L1-L15) - [MissionComp.ts](file://assets/script/game/map/MissionComp.ts#L1-L20) ### 外部依赖分析 | 依赖类型 | 组件名称 | 作用 | 影响范围 | |---------|----------|------|----------| | 框架依赖 | Oops Framework | 定时器管理、消息系统 | 全局功能 | | 引擎依赖 | Cocos Creator | 节点管理、组件系统 | 渲染层 | | 配置依赖 | SkillSet | 技能配置数据 | 业务逻辑 | | 事件依赖 | GameEvent | 事件通信机制 | 系统集成 | **章节来源** - [SkillConComp.ts](file://assets/script/game/hero/SkillConComp.ts#L1-L15) - [GameEvent.ts](file://assets/script/game/common/config/GameEvent.ts#L1-L70) ## 性能考量 ### 定时器性能优化 技能系统的定时器管理采用了多项性能优化策略: #### 定时器池化管理 - **批量清理**:使用`Object.values().forEach()`进行批量定时器清理 - **内存复用**:通过`_timers`对象实现定时器ID的集中管理 - **延迟清理**:在合适的时机(如`onDestroy`或`FightEnd`事件)进行清理 #### 性能监控指标 | 性能指标 | 目标值 | 监控方法 | 优化策略 | |---------|--------|----------|----------| | 定时器数量 | < 100个 | 运行时统计 | 实施清理阈值 | | 清理耗时 | < 16ms | 时间测量 | 异步清理 | | 内存占用 | < 10MB | 内存分析 | 对象池化 | ### 内存泄漏防护 系统通过多重防护机制防止内存泄漏: ```mermaid flowchart LR subgraph "防护层次" Level1["第一层:节点检查"] Level2["第二层:事件解绑"] Level3["第三层:组件销毁"] Level4["第四层:框架清理"] end Level1 --> Level2 Level2 --> Level3 Level3 --> Level4 subgraph "检测机制" LeakDetection["泄漏检测"] MemoryProfiling["内存分析"] ResourceTracking["资源追踪"] end Level4 --> LeakDetection LeakDetection --> MemoryProfiling MemoryProfiling --> ResourceTracking ``` **图表来源** - [SkillConComp.ts](file://assets/script/game/hero/SkillConComp.ts#L150-L177) ## 故障排除指南 ### 常见问题诊断 #### 定时器未清理问题 **症状表现**: - 浏览器内存持续增长 - 控制台出现定时器警告 - 技能执行异常延迟 **诊断步骤**: 1. 检查`_timers`对象是否正确初始化 2. 验证`onDestroy`方法是否被调用 3. 确认`FightEnd`事件是否正常触发 **解决方案**: ```typescript // 修复方案示例 public onDestroy() { // 确保清理所有定时器 Object.values(this._timers).forEach(clearTimeout); this._timers = {}; // 移除事件监听器 this.off(GameEvent.FightEnd); // 调用父类销毁方法 super.onDestroy(); } ``` #### 节点无效异常 **症状表现**: - 技能执行过程中抛出null引用异常 - 控制台出现"node is not valid"错误 **诊断方法**: - 在关键位置添加节点有效性检查 - 监控节点销毁时机 - 分析组件生命周期 **章节来源** - [SkillConComp.ts](file://assets/script/game/hero/SkillConComp.ts#L70-L75) - [SkillConComp.ts](file://assets/script/game/hero/SkillConComp.ts#L80-L85) ### 调试工具和技巧 #### 定时器状态监控 开发环境下可以通过以下方式监控定时器状态: | 监控项 | 检查方法 | 正常状态 | 异常状态 | |-------|----------|----------|----------| | 定时器数量 | `Object.keys(this._timers).length` | < 10 | > 100 | | 清理完整性 | `this._timers`对象状态 | `{}` | 包含未清理的定时器ID | | 事件监听器 | `this.has(GameEvent.FightEnd)` | `false` | `true` | #### 性能分析工具 推荐使用以下工具进行性能分析: - Chrome DevTools Memory面板 - Cocos Creator Profiler - 自定义定时器监控日志 **章节来源** - [SkillConComp.ts](file://assets/script/game/hero/SkillConComp.ts#L150-L177) ## 结论 技能执行资源管理系统通过多层次的定时器管理策略,实现了高效、安全的资源控制。系统的核心优势包括: ### 主要成就 1. **完善的生命周期管理**:通过`onDestroy`和`reset`方法确保组件销毁时的资源清理 2. **事件驱动的自动清理**:利用`FightEnd`事件实现战斗结束时的自动资源回收 3. **多重安全性检查**:在关键路径实施节点有效性检查,防止异常情况 4. **灵活的清理策略**:支持单个定时器清理和批量清理两种模式 ### 最佳实践总结 - **及时清理**:在组件销毁和战斗结束时立即清理定时器 - **安全性优先**:在每次关键操作前进行节点有效性检查 - **事件驱动**:利用事件系统实现自动化资源管理 - **异常处理**:在定时器回调中实施完善的异常处理机制 ### 未来改进方向 1. **异步清理优化**:考虑将大量定时器的清理操作异步化 2. **资源使用统计**:增加定时器使用情况的统计和分析功能 3. **自动泄漏检测**:实现定时器泄漏的自动检测和报告机制 4. **性能监控增强**:集成更详细的性能监控和告警系统 通过这套完整的技能执行资源管理策略,系统能够在保证功能完整性的同时,有效防止内存泄漏和资源浪费,为游戏的稳定运行提供坚实保障。