506 lines
17 KiB
Markdown
506 lines
17 KiB
Markdown
# 技能执行资源管理
|
||
|
||
<cite>
|
||
**本文档中引用的文件**
|
||
- [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)
|
||
</cite>
|
||
|
||
## 目录
|
||
1. [引言](#引言)
|
||
2. [项目结构概述](#项目结构概述)
|
||
3. [核心组件分析](#核心组件分析)
|
||
4. [架构概览](#架构概览)
|
||
5. [详细组件分析](#详细组件分析)
|
||
6. [依赖关系分析](#依赖关系分析)
|
||
7. [性能考量](#性能考量)
|
||
8. [故障排除指南](#故障排除指南)
|
||
9. [结论](#结论)
|
||
|
||
## 引言
|
||
|
||
在Cocos游戏引擎的战斗系统中,技能执行过程中的定时器资源管理是一个关键的系统级问题。本文档深入分析了技能执行过程中定时器资源的创建、存储、清理和生命周期管理策略,重点关注`_doSkill`方法中`setTimeout`创建的timerId如何被存储于`_timers`对象中,并通过`clear_timer`方法统一清除的完整流程。
|
||
|
||
## 项目结构概述
|
||
|
||
该项目采用基于组件的架构设计,技能系统的核心组件分布在以下目录结构中:
|
||
|
||
```mermaid
|
||
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.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<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
|
||
```
|
||
|
||
**图表来源**
|
||
- [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. **性能监控增强**:集成更详细的性能监控和告警系统
|
||
|
||
通过这套完整的技能执行资源管理策略,系统能够在保证功能完整性的同时,有效防止内存泄漏和资源浪费,为游戏的稳定运行提供坚实保障。 |