17 KiB
技能执行资源管理
**本文档中引用的文件** - [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)目录
引言
在Cocos游戏引擎的战斗系统中,技能执行过程中的定时器资源管理是一个关键的系统级问题。本文档深入分析了技能执行过程中定时器资源的创建、存储、清理和生命周期管理策略,重点关注_doSkill方法中setTimeout创建的timerId如何被存储于_timers对象中,并通过clear_timer方法统一清除的完整流程。
项目结构概述
该项目采用基于组件的架构设计,技能系统的核心组件分布在以下目录结构中:
graph TB
subgraph "技能系统架构"
SkillConComp["SkillConComp<br/>技能控制器组件"]
SkillEnt["SkillEnt<br/>技能实体管理"]
HeroViewComp["HeroViewComp<br/>英雄视图组件"]
MissionComp["MissionComp<br/>任务管理组件"]
end
subgraph "事件系统"
GameEvent["GameEvent<br/>游戏事件枚举"]
MessageSystem["消息系统<br/>事件分发"]
end
subgraph "定时器管理"
TimerModule["定时器模块<br/>Oops Framework"]
LocalTimers["_timers对象<br/>本地定时器存储"]
end
SkillConComp --> SkillEnt
SkillConComp --> HeroViewComp
MissionComp --> GameEvent
GameEvent --> MessageSystem
SkillConComp --> LocalTimers
TimerModule --> LocalTimers
图表来源
章节来源
核心组件分析
SkillConComp - 技能控制器组件
SkillConComp是技能系统的核心控制器,负责技能的施放、定时器管理和生命周期控制。该组件维护了一个私有的_timers对象,用于存储所有技能执行过程中创建的定时器ID。
主要特性:
- 定时器存储管理:使用
_timers: { [key: string]: any } = {}对象存储定时器 - 生命周期钩子:实现了
onDestroy和reset方法进行资源清理 - 事件监听:订阅
FightEnd事件进行自动清理 - 节点有效性检查:在多个关键点进行节点有效性验证
定时器管理流程:
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
图表来源
章节来源
架构概览
技能执行资源管理系统采用多层次的清理策略,确保定时器资源得到妥善管理:
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([资源清理完成])
图表来源
详细组件分析
定时器创建与存储机制
doSkill方法中的定时器创建
在doSkill方法中,技能执行采用了延迟执行模式,通过setTimeout创建定时器来延迟技能的实际执行:
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 : "依赖"
图表来源
定时器存储策略
定时器ID通过键值对形式存储在_timers对象中,键名采用skill_{uuid}格式,确保唯一性和可追溯性:
| 存储策略 | 优势 | 应用场景 |
|---|---|---|
| 键值对存储 | 支持按技能UUID快速查找和清理 | 单个技能的精确清理 |
| 对象引用 | 集合操作支持批量清理 | 批量资源清理 |
| 类型安全 | TypeScript类型约束 | 编译时错误预防 |
章节来源
生命周期钩子中的定时器清理
onDestroy方法的清理策略
onDestroy方法实现了组件销毁时的资源清理,这是防止内存泄漏的最后一道防线:
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
图表来源
reset方法的资源重置
reset方法提供了组件重置时的资源清理功能,主要用于组件池化场景:
| 清理阶段 | 操作内容 | 目的 |
|---|---|---|
| 定时器清理 | 调用clear_timer()方法 |
防止定时器残留 |
| 状态重置 | 重置内部状态变量 | 准备组件复用 |
| 事件解绑 | 解除事件监听器 | 避免内存泄漏 |
章节来源
FightEnd事件监听机制
战斗结束自动清理触发路径
战斗结束时的自动清理通过事件驱动机制实现,确保所有技能定时器得到及时清理:
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
图表来源
事件监听器的注册与管理
init方法中注册了FightEnd事件监听器,确保战斗结束时能够触发自动清理:
| 监听器类型 | 事件名称 | 回调函数 | 清理时机 |
|---|---|---|---|
| 单次监听 | FightEnd | clear_timer | 战斗结束时 |
| 生命周期监听 | onDestroy | 清理所有定时器 | 组件销毁时 |
| 事件解绑 | CastHeroSkill | 移除特定事件监听 | 组件销毁时 |
章节来源
异常场景下的安全性检查
节点有效性检查实践
在技能执行的关键路径上,实施了多层节点有效性检查,防止因节点被提前销毁而导致的异常:
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
图表来源
异常处理策略
| 异常类型 | 检查点 | 处理策略 | 预防措施 |
|---|---|---|---|
| 节点被销毁 | 每次关键操作前 | 提前返回,避免操作 | 定期检查节点有效性 |
| 英雄视图丢失 | 技能执行前 | 日志记录,跳过执行 | 保持对英雄状态的监控 |
| 定时器失效 | 定时器回调中 | 检查上下文有效性 | 使用闭包保护上下文 |
章节来源
依赖关系分析
组件间依赖关系
技能执行资源管理系统涉及多个组件间的复杂依赖关系:
graph TB
subgraph "核心组件"
SkillConComp["SkillConComp<br/>技能控制器"]
SkillEnt["SkillEnt<br/>技能实体"]
HeroViewComp["HeroViewComp<br/>英雄视图"]
end
subgraph "事件系统"
GameEvent["GameEvent<br/>事件枚举"]
MessageSystem["消息系统"]
end
subgraph "资源管理"
TimerModule["定时器模块"]
ComponentPool["组件池"]
end
subgraph "战斗系统"
MissionComp["MissionComp<br/>任务管理"]
BattleManager["战斗管理器"]
end
SkillConComp --> SkillEnt
SkillConComp --> HeroViewComp
SkillConComp --> TimerModule
SkillConComp --> GameEvent
GameEvent --> MessageSystem
MessageSystem --> SkillConComp
MissionComp --> BattleManager
BattleManager --> MessageSystem
SkillConComp -.-> ComponentPool
HeroViewComp -.-> ComponentPool
图表来源
外部依赖分析
| 依赖类型 | 组件名称 | 作用 | 影响范围 |
|---|---|---|---|
| 框架依赖 | Oops Framework | 定时器管理、消息系统 | 全局功能 |
| 引擎依赖 | Cocos Creator | 节点管理、组件系统 | 渲染层 |
| 配置依赖 | SkillSet | 技能配置数据 | 业务逻辑 |
| 事件依赖 | GameEvent | 事件通信机制 | 系统集成 |
章节来源
性能考量
定时器性能优化
技能系统的定时器管理采用了多项性能优化策略:
定时器池化管理
- 批量清理:使用
Object.values().forEach()进行批量定时器清理 - 内存复用:通过
_timers对象实现定时器ID的集中管理 - 延迟清理:在合适的时机(如
onDestroy或FightEnd事件)进行清理
性能监控指标
| 性能指标 | 目标值 | 监控方法 | 优化策略 |
|---|---|---|---|
| 定时器数量 | < 100个 | 运行时统计 | 实施清理阈值 |
| 清理耗时 | < 16ms | 时间测量 | 异步清理 |
| 内存占用 | < 10MB | 内存分析 | 对象池化 |
内存泄漏防护
系统通过多重防护机制防止内存泄漏:
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
图表来源
故障排除指南
常见问题诊断
定时器未清理问题
症状表现:
- 浏览器内存持续增长
- 控制台出现定时器警告
- 技能执行异常延迟
诊断步骤:
- 检查
_timers对象是否正确初始化 - 验证
onDestroy方法是否被调用 - 确认
FightEnd事件是否正常触发
解决方案:
// 修复方案示例
public onDestroy() {
// 确保清理所有定时器
Object.values(this._timers).forEach(clearTimeout);
this._timers = {};
// 移除事件监听器
this.off(GameEvent.FightEnd);
// 调用父类销毁方法
super.onDestroy();
}
节点无效异常
症状表现:
- 技能执行过程中抛出null引用异常
- 控制台出现"node is not valid"错误
诊断方法:
- 在关键位置添加节点有效性检查
- 监控节点销毁时机
- 分析组件生命周期
章节来源
调试工具和技巧
定时器状态监控
开发环境下可以通过以下方式监控定时器状态:
| 监控项 | 检查方法 | 正常状态 | 异常状态 |
|---|---|---|---|
| 定时器数量 | Object.keys(this._timers).length |
< 10 | > 100 |
| 清理完整性 | this._timers对象状态 |
{} |
包含未清理的定时器ID |
| 事件监听器 | this.has(GameEvent.FightEnd) |
false |
true |
性能分析工具
推荐使用以下工具进行性能分析:
- Chrome DevTools Memory面板
- Cocos Creator Profiler
- 自定义定时器监控日志
章节来源
结论
技能执行资源管理系统通过多层次的定时器管理策略,实现了高效、安全的资源控制。系统的核心优势包括:
主要成就
- 完善的生命周期管理:通过
onDestroy和reset方法确保组件销毁时的资源清理 - 事件驱动的自动清理:利用
FightEnd事件实现战斗结束时的自动资源回收 - 多重安全性检查:在关键路径实施节点有效性检查,防止异常情况
- 灵活的清理策略:支持单个定时器清理和批量清理两种模式
最佳实践总结
- 及时清理:在组件销毁和战斗结束时立即清理定时器
- 安全性优先:在每次关键操作前进行节点有效性检查
- 事件驱动:利用事件系统实现自动化资源管理
- 异常处理:在定时器回调中实施完善的异常处理机制
未来改进方向
- 异步清理优化:考虑将大量定时器的清理操作异步化
- 资源使用统计:增加定时器使用情况的统计和分析功能
- 自动泄漏检测:实现定时器泄漏的自动检测和报告机制
- 性能监控增强:集成更详细的性能监控和告警系统
通过这套完整的技能执行资源管理策略,系统能够在保证功能完整性的同时,有效防止内存泄漏和资源浪费,为游戏的稳定运行提供坚实保障。