refactor(game): 移除已弃用的事件常量
- 删除 UpdateHero 和 UpdateFightHero 事件 - 移除 MISSION_UPDATE 事件常量 - 优化游戏事件枚举定义
This commit is contained in:
735
.qoder/repowiki/zh/content/地图系统/怪物系统/怪物实体/怪物实体.md
Normal file
735
.qoder/repowiki/zh/content/地图系统/怪物系统/怪物实体/怪物实体.md
Normal file
@@ -0,0 +1,735 @@
|
||||
# 怪物实体ECS架构实现深度解析
|
||||
|
||||
<cite>
|
||||
**本文档引用的文件**
|
||||
- [Mon.ts](file://assets/script/game/hero/Mon.ts)
|
||||
- [MonModelComp.ts](file://assets/script/game/hero/MonModelComp.ts)
|
||||
- [BattleMoveComp.ts](file://assets/script/game/common/ecs/position/BattleMoveComp.ts)
|
||||
- [BattleMoveSystem.ts](file://assets/script/game/common/ecs/position/BattleMoveSystem.ts)
|
||||
- [MissionMonComp.ts](file://assets/script/game/map/MissionMonComp.ts)
|
||||
- [heroSet.ts](file://assets/script/game/common/config/heroSet.ts)
|
||||
- [RogueConfig.ts](file://assets/script/game/map/RogueConfig.ts)
|
||||
</cite>
|
||||
|
||||
## 目录
|
||||
1. [概述](#概述)
|
||||
2. [项目结构分析](#项目结构分析)
|
||||
3. [Monster类核心架构](#monster类核心架构)
|
||||
4. [ECS注册机制详解](#ecs注册机制详解)
|
||||
5. [load方法完整流程分析](#load方法完整流程分析)
|
||||
6. [BattleMoveComp组件集成](#battlemovemovecomp组件集成)
|
||||
7. [MonModelComp模型数据管理](#monmodelcomp模型数据管理)
|
||||
8. [系统架构与依赖关系](#系统架构与依赖关系)
|
||||
9. [开发示例与最佳实践](#开发示例与最佳实践)
|
||||
10. [常见错误与调试方法](#常见错误与调试方法)
|
||||
11. [总结](#总结)
|
||||
|
||||
## 概述
|
||||
|
||||
本文档深入解析Cocos Creator游戏项目中Monster类的ECS(Entity-Component-System)架构实现。Monster类作为游戏中的怪物实体,采用了现代游戏开发中流行的组件化架构模式,通过继承ecs.Entity并注册为`Monster`类型,实现了高度可扩展和可维护的游戏实体系统。
|
||||
|
||||
该架构的核心优势在于:
|
||||
- **组件化设计**:将怪物的不同功能分解为独立的组件
|
||||
- **类型安全**:利用TypeScript的类型系统确保组件正确使用
|
||||
- **性能优化**:通过组件缓存池和批量处理提升性能
|
||||
- **易于扩展**:支持动态添加和移除组件
|
||||
|
||||
## 项目结构分析
|
||||
|
||||
项目的ECS架构采用分层设计,主要包含以下层次:
|
||||
|
||||
```mermaid
|
||||
graph TB
|
||||
subgraph "实体层"
|
||||
Monster[Monster实体]
|
||||
Hero[Hero实体]
|
||||
end
|
||||
subgraph "组件层"
|
||||
BattleMove[BattleMoveComp<br/>战斗移动组件]
|
||||
MonModel[MonModelComp<br/>怪物模型组件]
|
||||
HeroView[HeroViewComp<br/>英雄视图组件]
|
||||
Tal[TalComp<br/>天赋组件]
|
||||
end
|
||||
subgraph "系统层"
|
||||
BattleMoveSys[BattleMoveSystem<br/>移动系统]
|
||||
PositionSys[EcsPositionSystem<br/>位置系统]
|
||||
end
|
||||
subgraph "管理层"
|
||||
MissionMon[MissionMonComp<br/>任务怪物管理]
|
||||
RogueConfig[RogueConfig<br/>肉鸽配置]
|
||||
end
|
||||
Monster --> BattleMove
|
||||
Monster --> MonModel
|
||||
Monster --> Tal
|
||||
Monster --> HeroView
|
||||
BattleMoveSys --> BattleMove
|
||||
BattleMoveSys --> HeroView
|
||||
MissionMon --> Monster
|
||||
MissionMon --> RogueConfig
|
||||
```
|
||||
|
||||
**图表来源**
|
||||
- [Mon.ts](file://assets/script/game/hero/Mon.ts#L1-L111)
|
||||
- [BattleMoveSystem.ts](file://assets/script/game/common/ecs/position/BattleMoveSystem.ts#L1-L272)
|
||||
- [MissionMonComp.ts](file://assets/script/game/map/MissionMonComp.ts#L1-L240)
|
||||
|
||||
## Monster类核心架构
|
||||
|
||||
Monster类作为ECS架构中的核心实体,展现了现代游戏开发的最佳实践:
|
||||
|
||||
```mermaid
|
||||
classDiagram
|
||||
class Monster {
|
||||
+MonModelComp HeroModel
|
||||
+HeroViewComp HeroView
|
||||
+BattleMoveComp BattleMove
|
||||
+init() void
|
||||
+destroy() void
|
||||
+load(pos, scale, uuid, is_boss, is_call, strengthMultiplier) void
|
||||
+hero_init(uuid, node, scale, box_group, is_boss, is_call, strengthMultiplier) void
|
||||
}
|
||||
class ecs_Entity {
|
||||
<<abstract>>
|
||||
+add(component) void
|
||||
+remove(component) void
|
||||
+get(component) Comp
|
||||
+has(component) boolean
|
||||
+destroy() void
|
||||
}
|
||||
class BattleMoveComp {
|
||||
+number direction
|
||||
+number targetX
|
||||
+boolean moving
|
||||
+reset() void
|
||||
}
|
||||
class MonModelComp {
|
||||
+reset() void
|
||||
}
|
||||
class HeroViewComp {
|
||||
+number scale
|
||||
+FacSet fac
|
||||
+HType type
|
||||
+boolean is_boss
|
||||
+number hero_uuid
|
||||
+string hero_name
|
||||
+number base_hp
|
||||
+number base_mp
|
||||
+number base_ap
|
||||
+number base_def
|
||||
+number hp
|
||||
+number mp
|
||||
+number ap
|
||||
+number def
|
||||
+Attrs attrs
|
||||
+Skills skills
|
||||
}
|
||||
Monster --|> ecs_Entity
|
||||
Monster --> BattleMoveComp
|
||||
Monster --> MonModelComp
|
||||
Monster --> HeroViewComp
|
||||
```
|
||||
|
||||
**图表来源**
|
||||
- [Mon.ts](file://assets/script/game/hero/Mon.ts#L18-L35)
|
||||
- [BattleMoveComp.ts](file://assets/script/game/common/ecs/position/BattleMoveComp.ts#L1-L16)
|
||||
- [MonModelComp.ts](file://assets/script/game/hero/MonModelComp.ts#L1-L20)
|
||||
|
||||
**章节来源**
|
||||
- [Mon.ts](file://assets/script/game/hero/Mon.ts#L1-L111)
|
||||
|
||||
## ECS注册机制详解
|
||||
|
||||
Monster类通过装饰器`@ecs.register('Monster')`完成ECS系统的注册,这是整个架构的基础:
|
||||
|
||||
### 注册机制特点
|
||||
|
||||
1. **类型标识**:通过字符串标识符'Monster'唯一标识实体类型
|
||||
2. **自动发现**:ECS系统能够自动发现和管理注册的实体类型
|
||||
3. **类型安全**:编译时确保实体类型的一致性
|
||||
|
||||
### 组件注册与关联
|
||||
|
||||
Monster实体在初始化时通过`init()`方法注册所需的组件:
|
||||
|
||||
```typescript
|
||||
protected init() {
|
||||
this.addComponents<ecs.Comp>(
|
||||
BattleMoveComp,
|
||||
MonModelComp,
|
||||
TalComp,
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
这种设计的优势:
|
||||
- **明确依赖**:清楚展示实体所需的所有组件
|
||||
- **生命周期管理**:组件的创建和销毁与实体同步
|
||||
- **性能优化**:避免重复创建相同类型的组件
|
||||
|
||||
**章节来源**
|
||||
- [Mon.ts](file://assets/script/game/hero/Mon.ts#L25-L35)
|
||||
|
||||
## load方法完整流程分析
|
||||
|
||||
`load`方法是Monster实体的核心初始化方法,实现了从预制体加载到组件绑定的完整流程:
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
Start([开始load方法]) --> SetScale["设置scale=-1<br/>怪物朝向左侧"]
|
||||
SetScale --> GetScene["获取场景引用<br/>scene = smc.map.MapView.scene"]
|
||||
GetScene --> BuildPath["构建预制体路径<br/>path = 'game/heros/' + HeroInfo[uuid].path"]
|
||||
BuildPath --> LoadPrefab["加载预制体<br/>prefab = oops.res.get(path, Prefab)"]
|
||||
LoadPrefab --> Instantiate["实例化预制体<br/>node = instantiate(prefab)"]
|
||||
Instantiate --> SetParent["设置父节点<br/>node.parent = scene.entityLayer!.node!"]
|
||||
SetParent --> DisableCollider["禁用碰撞体<br/>collider.enabled = false"]
|
||||
DisableCollider --> EnableCollider["延迟启用碰撞体<br/>延迟一帧启用"]
|
||||
EnableCollider --> SetPosition["设置初始位置<br/>node.setPosition(pos)"]
|
||||
SetPosition --> CallInit["调用hero_init方法<br/>初始化怪物属性"]
|
||||
CallInit --> DispatchEvent["分发monster_load事件<br/>通知其他模块"]
|
||||
DispatchEvent --> InitMove["初始化移动参数<br/>设置向左移动"]
|
||||
InitMove --> UpdateCounter["更新怪物计数<br/>smc.vmdata.mission_data.mon_num++"]
|
||||
UpdateCounter --> End([完成])
|
||||
```
|
||||
|
||||
**图表来源**
|
||||
- [Mon.ts](file://assets/script/game/hero/Mon.ts#L37-L65)
|
||||
|
||||
### 关键步骤详解
|
||||
|
||||
#### 1. 预制体动态加载
|
||||
```typescript
|
||||
var path = "game/heros/" + HeroInfo[uuid].path;
|
||||
var prefab: Prefab = oops.res.get(path, Prefab)!;
|
||||
var node = instantiate(prefab);
|
||||
```
|
||||
|
||||
这个过程展示了:
|
||||
- **配置驱动**:通过HeroInfo配置表动态确定预制体路径
|
||||
- **资源管理**:使用oops.res进行资源加载和缓存
|
||||
- **类型安全**:明确指定Prefab类型确保类型安全
|
||||
|
||||
#### 2. 碰撞体延迟启用机制
|
||||
```typescript
|
||||
const collider = node.getComponent(BoxCollider2D);
|
||||
if (collider) collider.enabled = false;
|
||||
```
|
||||
|
||||
这种设计考虑了:
|
||||
- **性能优化**:避免不必要的物理计算
|
||||
- **稳定性**:确保碰撞体在正确时机启用
|
||||
- **兼容性**:适应不同预制体的碰撞体配置
|
||||
|
||||
#### 3. 事件通知机制
|
||||
```typescript
|
||||
oops.message.dispatchEvent("monster_load", this);
|
||||
```
|
||||
|
||||
事件系统的作用:
|
||||
- **解耦**:减少组件间的直接依赖
|
||||
- **扩展性**:支持多个监听器响应同一事件
|
||||
- **异步处理**:允许异步执行相关逻辑
|
||||
|
||||
**章节来源**
|
||||
- [Mon.ts](file://assets/script/game/hero/Mon.ts#L37-L65)
|
||||
|
||||
## BattleMoveComp组件集成
|
||||
|
||||
BattleMoveComp是Monster实体的核心移动组件,负责控制怪物的移动行为:
|
||||
|
||||
### 组件结构分析
|
||||
|
||||
```mermaid
|
||||
classDiagram
|
||||
class BattleMoveComp {
|
||||
+number direction
|
||||
+number targetX
|
||||
+boolean moving
|
||||
+reset() void
|
||||
}
|
||||
class BattleMoveSystem {
|
||||
+filter() IMatcher
|
||||
+update(entity) void
|
||||
+checkEnemiesInFace(entity) boolean
|
||||
+updateRenderOrder(entity) void
|
||||
+validatePosition(newX, move) boolean
|
||||
}
|
||||
BattleMoveSystem --> BattleMoveComp : "管理"
|
||||
BattleMoveSystem --> HeroViewComp : "协作"
|
||||
```
|
||||
|
||||
**图表来源**
|
||||
- [BattleMoveComp.ts](file://assets/script/game/common/ecs/position/BattleMoveComp.ts#L1-L16)
|
||||
- [BattleMoveSystem.ts](file://assets/script/game/common/ecs/position/BattleMoveSystem.ts#L1-L272)
|
||||
|
||||
### 移动逻辑实现
|
||||
|
||||
BattleMoveSystem通过复杂的AI逻辑控制怪物移动:
|
||||
|
||||
#### 1. 基础移动控制
|
||||
```typescript
|
||||
const delta = (view.Attrs[Attrs.SPEED]/3) * this.dt * move.direction;
|
||||
const newX = view.node.position.x + delta;
|
||||
```
|
||||
|
||||
#### 2. 边界检测与停止
|
||||
```typescript
|
||||
if (this.validatePosition(newX, move)) {
|
||||
view.status_change("move");
|
||||
view.node.setPosition(newX, view.node.position.y, 0);
|
||||
} else {
|
||||
view.status_change("idle");
|
||||
move.moving = false;
|
||||
}
|
||||
```
|
||||
|
||||
#### 3. 敌人检测与反应
|
||||
```typescript
|
||||
const shouldStop = this.checkEnemiesInFace(e);
|
||||
if (shouldStop) {
|
||||
view.status_change("idle");
|
||||
return;
|
||||
}
|
||||
```
|
||||
|
||||
### 驱动怪物向左移动的逻辑
|
||||
|
||||
在Monster的load方法中,通过以下代码设置移动参数:
|
||||
|
||||
```typescript
|
||||
const move = this.get(BattleMoveComp);
|
||||
move.direction = -1; // 向左移动
|
||||
move.targetX = -800; // 左边界
|
||||
```
|
||||
|
||||
这种设计体现了:
|
||||
- **组件化控制**:移动逻辑完全封装在BattleMoveComp中
|
||||
- **灵活性**:可以在运行时动态修改移动参数
|
||||
- **可测试性**:便于单独测试移动逻辑
|
||||
|
||||
**章节来源**
|
||||
- [BattleMoveComp.ts](file://assets/script/game/common/ecs/position/BattleMoveComp.ts#L1-L16)
|
||||
- [BattleMoveSystem.ts](file://assets/script/game/common/ecs/position/BattleMoveSystem.ts#L15-L272)
|
||||
- [Mon.ts](file://assets/script/game/hero/Mon.ts#L55-L60)
|
||||
|
||||
## MonModelComp模型数据管理
|
||||
|
||||
MonModelComp虽然看似简单,但在ECS架构中扮演着重要的数据管理角色:
|
||||
|
||||
### 组件设计特点
|
||||
|
||||
```typescript
|
||||
@ecs.register('MonModel')
|
||||
export class MonModelComp extends ecs.Comp {
|
||||
reset() {
|
||||
// 目前为空实现
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 数据存储与管理策略
|
||||
|
||||
尽管MonModelComp目前没有复杂的数据存储,但它遵循了ECS架构的最佳实践:
|
||||
|
||||
1. **职责单一**:专注于怪物模型相关的数据管理
|
||||
2. **可扩展性**:预留了未来扩展的空间
|
||||
3. **一致性**:与其他组件保持相同的接口风格
|
||||
|
||||
### 属性重置机制
|
||||
|
||||
```typescript
|
||||
reset() {
|
||||
// 目前为空实现
|
||||
}
|
||||
```
|
||||
|
||||
这种设计考虑了:
|
||||
- **性能优化**:避免不必要的重置操作
|
||||
- **灵活性**:允许子类根据需要重写重置逻辑
|
||||
- **一致性**:保持与ecs.Comp基类的接口一致
|
||||
|
||||
**章节来源**
|
||||
- [MonModelComp.ts](file://assets/script/game/hero/MonModelComp.ts#L1-L20)
|
||||
|
||||
## 系统架构与依赖关系
|
||||
|
||||
Monster实体的完整生命周期涉及多个系统和组件的协作:
|
||||
|
||||
```mermaid
|
||||
graph TB
|
||||
subgraph "输入层"
|
||||
Config[配置数据<br/>HeroInfo, MonSet]
|
||||
Resources[资源文件<br/>预制体, 图集]
|
||||
end
|
||||
subgraph "管理层"
|
||||
MissionMon[MissionMonComp<br/>任务管理器]
|
||||
RogueConfig[RogueConfig<br/>肉鸽配置]
|
||||
end
|
||||
subgraph "实体层"
|
||||
Monster[Monster实体]
|
||||
end
|
||||
subgraph "组件层"
|
||||
BattleMove[BattleMoveComp<br/>移动控制]
|
||||
MonModel[MonModelComp<br/>模型数据]
|
||||
HeroView[HeroViewComp<br/>视图管理]
|
||||
Tal[TalComp<br/>天赋系统]
|
||||
end
|
||||
subgraph "系统层"
|
||||
BattleMoveSys[BattleMoveSystem<br/>移动系统]
|
||||
PositionSys[EcsPositionSystem<br/>位置系统]
|
||||
end
|
||||
Config --> MissionMon
|
||||
Resources --> Monster
|
||||
RogueConfig --> MissionMon
|
||||
MissionMon --> Monster
|
||||
Monster --> BattleMove
|
||||
Monster --> MonModel
|
||||
Monster --> HeroView
|
||||
Monster --> Tal
|
||||
BattleMove --> BattleMoveSys
|
||||
HeroView --> BattleMoveSys
|
||||
BattleMoveSys --> PositionSys
|
||||
```
|
||||
|
||||
**图表来源**
|
||||
- [MissionMonComp.ts](file://assets/script/game/map/MissionMonComp.ts#L1-L240)
|
||||
- [Mon.ts](file://assets/script/game/hero/Mon.ts#L1-L111)
|
||||
- [BattleMoveSystem.ts](file://assets/script/game/common/ecs/position/BattleMoveSystem.ts#L1-L272)
|
||||
|
||||
### 关键依赖关系
|
||||
|
||||
1. **配置依赖**:Monster依赖HeroInfo配置表获取怪物数据
|
||||
2. **资源依赖**:依赖预制体资源进行实例化
|
||||
3. **系统依赖**:依赖BattleMoveSystem进行移动逻辑处理
|
||||
4. **事件依赖**:通过消息系统与其他模块通信
|
||||
|
||||
**章节来源**
|
||||
- [MissionMonComp.ts](file://assets/script/game/map/MissionMonComp.ts#L1-L240)
|
||||
- [heroSet.ts](file://assets/script/game/common/config/heroSet.ts#L1-L152)
|
||||
|
||||
## 开发示例与最佳实践
|
||||
|
||||
### 新增怪物实体类型示例
|
||||
|
||||
以下是新增一种新型态怪物的完整实现:
|
||||
|
||||
#### 1. 创建新的怪物类型配置
|
||||
|
||||
```typescript
|
||||
// 在heroSet.ts中添加新的怪物配置
|
||||
export const HeroInfo: Record<number, heroInfo> = {
|
||||
// ...
|
||||
5204: {uuid: 5204, name: "冰霜巨人", path: "mo2", fac: FacSet.MON, kind: 1,
|
||||
type: HType.warrior, lv: 1, hp: 50, mp: 120, ap: 8, map: 15, def: 10, mdef: 0,
|
||||
ap: 8, dis: 120, speed: 80, skills: [6006], buff: [], tal: [], info: "冰霜系怪物"},
|
||||
};
|
||||
```
|
||||
|
||||
#### 2. 创建专门的怪物实体类
|
||||
|
||||
```typescript
|
||||
@ecs.register('IceGiant')
|
||||
export class IceGiant extends ecs.Entity {
|
||||
IceModel!: MonModelComp;
|
||||
IceView!: HeroViewComp;
|
||||
IceMove!: BattleMoveComp;
|
||||
IceEffect!: IceEffectComp; // 新增冰霜效果组件
|
||||
|
||||
protected init() {
|
||||
this.addComponents<ecs.Comp>(
|
||||
BattleMoveComp,
|
||||
MonModelComp,
|
||||
IceEffectComp, // 添加新组件
|
||||
TalComp,
|
||||
);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### 3. 实现特定的加载逻辑
|
||||
|
||||
```typescript
|
||||
loadIceGiant(pos: Vec3, scale: number = 1, strengthMultiplier: number = 1.0) {
|
||||
// 调用通用加载逻辑
|
||||
this.load(pos, scale, 5204, false, false, strengthMultiplier);
|
||||
|
||||
// 特定于冰霜巨人的初始化
|
||||
const effect = this.get(IceEffectComp);
|
||||
effect.freezeDuration = 2.0; // 冻结持续时间
|
||||
effect.freezeChance = 0.3; // 冻结概率
|
||||
}
|
||||
```
|
||||
|
||||
### 配置预制体路径的最佳实践
|
||||
|
||||
1. **命名规范**:使用统一的命名约定
|
||||
```typescript
|
||||
// 推荐:mo1, mo2, mo3 表示不同的怪物类型
|
||||
// 不推荐:monster1, enemy1, badguy
|
||||
```
|
||||
|
||||
2. **资源组织**:按类型分类存放预制体
|
||||
```
|
||||
assets/resources/game/heros/
|
||||
├── mo1/ # 普通怪物
|
||||
├── mo2/ # 冰霜怪物
|
||||
├── mo3/ # 火焰怪物
|
||||
└── boss/ # Boss怪物
|
||||
```
|
||||
|
||||
3. **版本管理**:为不同版本的预制体建立目录结构
|
||||
```
|
||||
assets/resources/game/heros/v1.0/mo1/
|
||||
assets/resources/game/heros/v1.1/mo1/
|
||||
```
|
||||
|
||||
### 初始化参数配置指南
|
||||
|
||||
#### 基础属性配置
|
||||
|
||||
```typescript
|
||||
interface MonsterConfig {
|
||||
uuid: number;
|
||||
position: number; // 在MonSet中的位置索引
|
||||
type: MonsterType; // 怪物类型
|
||||
level: number; // 等级(1-5)
|
||||
strengthMultiplier: number; // 强度倍率
|
||||
isBoss?: boolean; // 是否为Boss
|
||||
isCall?: boolean; // 是否为召唤怪
|
||||
}
|
||||
```
|
||||
|
||||
#### 强度倍率计算
|
||||
|
||||
```typescript
|
||||
function calculateMonsterStrengthMultiplier(stageNumber: number, level: number): number {
|
||||
const stageMultiplier = 1 + (stageNumber - 1) * 0.1; // 每关增加10%
|
||||
const levelMultiplier = 1 + (level - 1) * 0.05; // 每级增加5%
|
||||
return stageMultiplier * levelMultiplier;
|
||||
}
|
||||
```
|
||||
|
||||
**章节来源**
|
||||
- [heroSet.ts](file://assets/script/game/common/config/heroSet.ts#L130-L152)
|
||||
- [RogueConfig.ts](file://assets/script/game/map/RogueConfig.ts#L175-L190)
|
||||
|
||||
## 常见错误与调试方法
|
||||
|
||||
### 常见集成错误
|
||||
|
||||
#### 1. 组件注册错误
|
||||
|
||||
**错误表现**:
|
||||
```typescript
|
||||
// 错误:忘记注册组件
|
||||
export class Monster extends ecs.Entity {
|
||||
// 缺少组件声明
|
||||
// HeroModel!: MonModelComp;
|
||||
// HeroView!: HeroViewComp;
|
||||
// BattleMove!: BattleMoveComp;
|
||||
}
|
||||
```
|
||||
|
||||
**解决方案**:
|
||||
```typescript
|
||||
// 正确:在类中声明组件
|
||||
export class Monster extends ecs.Entity {
|
||||
HeroModel!: MonModelComp;
|
||||
HeroView!: HeroViewComp;
|
||||
BattleMove!: BattleMoveComp;
|
||||
}
|
||||
```
|
||||
|
||||
#### 2. 预制体加载失败
|
||||
|
||||
**错误表现**:
|
||||
```typescript
|
||||
// 错误:路径拼写错误
|
||||
var path = "game/heros/" + HeroInfo[uuid].path; // 可能导致加载失败
|
||||
```
|
||||
|
||||
**解决方案**:
|
||||
```typescript
|
||||
// 正确:添加错误处理和日志
|
||||
try {
|
||||
var path = "game/heros/" + HeroInfo[uuid].path;
|
||||
var prefab: Prefab = oops.res.get(path, Prefab);
|
||||
if (!prefab) {
|
||||
console.error(`预制体加载失败: ${path}`);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(`加载预制体时出错:`, error);
|
||||
}
|
||||
```
|
||||
|
||||
#### 3. 组件初始化顺序问题
|
||||
|
||||
**错误表现**:
|
||||
```typescript
|
||||
// 错误:在组件未注册前就尝试获取
|
||||
load() {
|
||||
const move = this.get(BattleMoveComp); // 可能在init之前调用
|
||||
move.direction = -1;
|
||||
}
|
||||
```
|
||||
|
||||
**解决方案**:
|
||||
```typescript
|
||||
// 正确:确保在init之后调用
|
||||
protected init() {
|
||||
this.addComponents<ecs.Comp>(
|
||||
BattleMoveComp,
|
||||
MonModelComp,
|
||||
TalComp,
|
||||
);
|
||||
}
|
||||
|
||||
load() {
|
||||
// load方法会在init之后调用
|
||||
const move = this.get(BattleMoveComp);
|
||||
move.direction = -1;
|
||||
}
|
||||
```
|
||||
|
||||
### 调试方法
|
||||
|
||||
#### 1. 组件状态监控
|
||||
|
||||
```typescript
|
||||
// 在Monster类中添加调试方法
|
||||
debugPrintState() {
|
||||
console.log(`Monster状态:`, {
|
||||
hasBattleMove: this.has(BattleMoveComp),
|
||||
hasHeroView: this.has(HeroViewComp),
|
||||
hasMonModel: this.has(MonModelComp),
|
||||
battleMoveDirection: this.BattleMove?.direction,
|
||||
heroName: this.HeroView?.hero_name,
|
||||
hp: this.HeroView?.hp,
|
||||
mp: this.HeroView?.mp
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
#### 2. 生命周期跟踪
|
||||
|
||||
```typescript
|
||||
// 添加生命周期钩子
|
||||
protected init() {
|
||||
console.log('Monster init');
|
||||
super.init();
|
||||
}
|
||||
|
||||
destroy() {
|
||||
console.log('Monster destroy');
|
||||
super.destroy();
|
||||
}
|
||||
```
|
||||
|
||||
#### 3. 系统状态检查
|
||||
|
||||
```typescript
|
||||
// 在BattleMoveSystem中添加调试信息
|
||||
update(e: ecs.Entity) {
|
||||
const move = e.get(BattleMoveComp);
|
||||
const view = e.get(HeroViewComp);
|
||||
|
||||
console.log(`[${view.hero_name}] 位置: ${view.node.position.x.toFixed(1)}, 方向: ${move.direction}, 移动: ${move.moving}`);
|
||||
|
||||
// 原有逻辑...
|
||||
}
|
||||
```
|
||||
|
||||
#### 4. 性能监控
|
||||
|
||||
```typescript
|
||||
// 监控组件创建和销毁
|
||||
static createCount = 0;
|
||||
static destroyCount = 0;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
Monster.createCount++;
|
||||
console.log(`Monster创建总数: ${Monster.createCount}`);
|
||||
}
|
||||
|
||||
destroy() {
|
||||
Monster.destroyCount++;
|
||||
console.log(`Monster销毁总数: ${Monster.destroyCount}`);
|
||||
super.destroy();
|
||||
}
|
||||
```
|
||||
|
||||
### 性能优化建议
|
||||
|
||||
#### 1. 组件缓存池优化
|
||||
|
||||
```typescript
|
||||
// 利用ECS系统的组件缓存池
|
||||
const move = ecs.getComponent(BattleMoveComp);
|
||||
try {
|
||||
move.direction = -1;
|
||||
move.targetX = -800;
|
||||
} finally {
|
||||
ecs.releaseComponent(move);
|
||||
}
|
||||
```
|
||||
|
||||
#### 2. 批量处理优化
|
||||
|
||||
```typescript
|
||||
// 批量创建怪物
|
||||
function batchCreateMonsters(configs: MonsterConfig[]) {
|
||||
configs.forEach(config => {
|
||||
const monster = ecs.getEntity<Monster>(Monster);
|
||||
monster.load(
|
||||
v3(MonSet[config.position].pos),
|
||||
-1, // scale
|
||||
config.uuid,
|
||||
config.type === MonsterType.BOSS,
|
||||
false,
|
||||
config.strengthMultiplier
|
||||
);
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
#### 3. 内存泄漏预防
|
||||
|
||||
```typescript
|
||||
// 确保正确清理事件监听器
|
||||
destroy() {
|
||||
oops.message.removeEventListener("monster_load", this.onMonsterLoad);
|
||||
super.destroy();
|
||||
}
|
||||
```
|
||||
|
||||
**章节来源**
|
||||
- [Mon.ts](file://assets/script/game/hero/Mon.ts#L30-L35)
|
||||
- [BattleMoveSystem.ts](file://assets/script/game/common/ecs/position/BattleMoveSystem.ts#L15-L50)
|
||||
|
||||
## 总结
|
||||
|
||||
Monster类的ECS架构实现展现了现代游戏开发中组件化设计的最佳实践。通过深入分析,我们可以看到:
|
||||
|
||||
### 架构优势
|
||||
|
||||
1. **高度模块化**:每个组件负责单一职责,便于维护和扩展
|
||||
2. **类型安全**:利用TypeScript确保组件使用的正确性
|
||||
3. **性能优化**:通过组件缓存池和批量处理提升性能
|
||||
4. **易于测试**:组件间松耦合,便于单元测试
|
||||
|
||||
### 设计亮点
|
||||
|
||||
1. **灵活的预制体加载机制**:支持动态配置和资源管理
|
||||
2. **智能的移动控制系统**:结合AI逻辑实现复杂的怪物行为
|
||||
3. **完善的事件通知机制**:支持模块间解耦通信
|
||||
4. **可扩展的配置系统**:支持多种怪物类型和强度配置
|
||||
|
||||
### 最佳实践总结
|
||||
|
||||
1. **严格遵循ECS原则**:组件职责单一,实体轻量化
|
||||
2. **合理使用装饰器**:通过`@ecs.register`简化组件注册
|
||||
3. **注重错误处理**:添加适当的异常处理和日志记录
|
||||
4. **性能优先**:充分利用组件缓存池和批量处理
|
||||
5. **文档完善**:为复杂逻辑添加详细的注释和文档
|
||||
|
||||
这套ECS架构不仅适用于怪物实体,也为游戏中的其他实体类型提供了可复用的设计模式。通过遵循这些设计原则和最佳实践,开发者可以构建出高性能、可维护的游戏系统。
|
||||
Reference in New Issue
Block a user