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架构不仅适用于怪物实体,也为游戏中的其他实体类型提供了可复用的设计模式。通过遵循这些设计原则和最佳实践,开发者可以构建出高性能、可维护的游戏系统。
|
||||
580
.qoder/repowiki/zh/content/地图系统/怪物系统/怪物实体/怪物实体初始化流程.md
Normal file
580
.qoder/repowiki/zh/content/地图系统/怪物系统/怪物实体/怪物实体初始化流程.md
Normal file
@@ -0,0 +1,580 @@
|
||||
# 怪物实体初始化流程
|
||||
|
||||
<cite>
|
||||
**本文档中引用的文件**
|
||||
- [Mon.ts](file://assets/script/game/hero/Mon.ts)
|
||||
- [MissionMonComp.ts](file://assets/script/game/map/MissionMonComp.ts)
|
||||
- [heroSet.ts](file://assets/script/game/common/config/heroSet.ts)
|
||||
- [SkillSet.ts](file://assets/script/game/common/config/SkillSet.ts)
|
||||
- [HeroAttrs.ts](file://assets/script/game/common/config/HeroAttrs.ts)
|
||||
- [EntityLayer.ts](file://assets/script/game/map/view/map/layer/entityLayer.ts)
|
||||
- [BoxSet.ts](file://assets/script/game/common/config/BoxSet.ts)
|
||||
- [GameEvent.ts](file://assets/script/game/common/config/GameEvent.ts)
|
||||
</cite>
|
||||
|
||||
## 目录
|
||||
1. [概述](#概述)
|
||||
2. [项目结构分析](#项目结构分析)
|
||||
3. [核心组件架构](#核心组件架构)
|
||||
4. [Monster类load方法详解](#monster类load方法详解)
|
||||
5. [hero_init方法深度解析](#hero_init方法深度解析)
|
||||
6. [资源加载与预制体管理](#资源加载与预制体管理)
|
||||
7. [场景节点挂载机制](#场景节点挂载机制)
|
||||
8. [消息事件系统](#消息事件系统)
|
||||
9. [异常处理与调试策略](#异常处理与调试策略)
|
||||
10. [实际应用示例](#实际应用示例)
|
||||
11. [总结](#总结)
|
||||
|
||||
## 概述
|
||||
|
||||
Monster类是游戏中的核心怪物实体管理器,负责怪物的完整生命周期管理,包括预制体加载、属性初始化、技能配置、碰撞体控制等关键功能。本文档将深入解析Monster类中load方法的完整初始化流程,重点阐述其动态加载机制、属性调整逻辑以及与其他系统的集成方式。
|
||||
|
||||
## 项目结构分析
|
||||
|
||||
```mermaid
|
||||
graph TB
|
||||
subgraph "怪物系统架构"
|
||||
A[Monster类] --> B[load方法]
|
||||
A --> C[hero_init方法]
|
||||
B --> D[预制体加载]
|
||||
B --> E[节点挂载]
|
||||
B --> F[碰撞体控制]
|
||||
C --> G[属性初始化]
|
||||
C --> H[技能配置]
|
||||
C --> I[Buff系统]
|
||||
end
|
||||
subgraph "配置系统"
|
||||
J[HeroInfo配置] --> K[基础属性]
|
||||
J --> L[技能列表]
|
||||
M[SkillSet配置] --> N[技能数据]
|
||||
O[BoxSet配置] --> P[碰撞组]
|
||||
end
|
||||
subgraph "场景系统"
|
||||
Q[EntityLayer] --> R[节点管理]
|
||||
S[MapView] --> T[场景容器]
|
||||
end
|
||||
A --> J
|
||||
A --> M
|
||||
B --> Q
|
||||
B --> S
|
||||
```
|
||||
|
||||
**图表来源**
|
||||
- [Mon.ts](file://assets/script/game/hero/Mon.ts#L14-L110)
|
||||
- [heroSet.ts](file://assets/script/game/common/config/heroSet.ts#L70-L151)
|
||||
|
||||
**章节来源**
|
||||
- [Mon.ts](file://assets/script/game/hero/Mon.ts#L1-L110)
|
||||
- [heroSet.ts](file://assets/script/game/common/config/heroSet.ts#L1-L151)
|
||||
|
||||
## 核心组件架构
|
||||
|
||||
Monster类采用ECS(Entity-Component-System)架构模式,继承自ecs.Entity基类,包含以下核心组件:
|
||||
|
||||
```mermaid
|
||||
classDiagram
|
||||
class Monster {
|
||||
+HeroModel! MonModelComp
|
||||
+HeroView! HeroViewComp
|
||||
+BattleMove! BattleMoveComp
|
||||
+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 MonModelComp {
|
||||
+reset() void
|
||||
}
|
||||
class HeroViewComp {
|
||||
+scale number
|
||||
+fac FacSet
|
||||
+type HType
|
||||
+is_boss boolean
|
||||
+box_group BoxSet
|
||||
+hero_uuid number
|
||||
+hero_name string
|
||||
+base_hp number
|
||||
+base_mp number
|
||||
+base_ap number
|
||||
+base_def number
|
||||
+skills Skill[]
|
||||
+Attrs Attrs
|
||||
+initAttrs() void
|
||||
}
|
||||
class BattleMoveComp {
|
||||
+direction number
|
||||
+targetX number
|
||||
}
|
||||
Monster --> MonModelComp : "包含"
|
||||
Monster --> HeroViewComp : "包含"
|
||||
Monster --> BattleMoveComp : "包含"
|
||||
```
|
||||
|
||||
**图表来源**
|
||||
- [Mon.ts](file://assets/script/game/hero/Mon.ts#L14-L35)
|
||||
- [MonModelComp.ts](file://assets/script/game/hero/MonModelComp.ts#L10-L18)
|
||||
|
||||
**章节来源**
|
||||
- [Mon.ts](file://assets/script/game/hero/Mon.ts#L14-L35)
|
||||
|
||||
## Monster类load方法详解
|
||||
|
||||
load方法是Monster类的核心初始化入口,负责完整的怪物实体创建流程:
|
||||
|
||||
### 方法签名与参数说明
|
||||
|
||||
| 参数名 | 类型 | 默认值 | 说明 |
|
||||
|--------|------|--------|------|
|
||||
| pos | Vec3 | Vec3.ZERO | 怪物初始位置坐标 |
|
||||
| scale | number | 1 | 怪物缩放比例 |
|
||||
| uuid | number | 1001 | 怪物唯一标识符 |
|
||||
| is_boss | boolean | false | 是否为Boss怪物 |
|
||||
| is_call | boolean | false | 是否为召唤怪物 |
|
||||
| strengthMultiplier | number | 1.0 | 强度倍率 |
|
||||
|
||||
### 完整初始化流程
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
A[开始load方法] --> B[设置缩放参数]
|
||||
B --> C[确定碰撞组]
|
||||
C --> D[获取场景引用]
|
||||
D --> E[构建资源路径]
|
||||
E --> F[加载预制体]
|
||||
F --> G{预制体加载成功?}
|
||||
G --> |否| H[抛出异常]
|
||||
G --> |是| I[创建节点实例]
|
||||
I --> J[设置父节点]
|
||||
J --> K[禁用碰撞体]
|
||||
K --> L[设置初始位置]
|
||||
L --> M[调用hero_init]
|
||||
M --> N[派发monster_load事件]
|
||||
N --> O[初始化移动参数]
|
||||
O --> P[更新怪物计数]
|
||||
P --> Q[结束]
|
||||
H --> R[错误处理]
|
||||
R --> Q
|
||||
```
|
||||
|
||||
**图表来源**
|
||||
- [Mon.ts](file://assets/script/game/hero/Mon.ts#L36-L60)
|
||||
|
||||
### 关键实现细节
|
||||
|
||||
#### 1. 动态资源路径构建
|
||||
```typescript
|
||||
// 资源路径格式:game/heros/{hero.path}
|
||||
var path = "game/heros/" + HeroInfo[uuid].path;
|
||||
```
|
||||
|
||||
#### 2. 碰撞体延迟启用机制
|
||||
```typescript
|
||||
// 先禁用碰撞体,延迟一帧启用
|
||||
const collider = node.getComponent(BoxCollider2D);
|
||||
if (collider) collider.enabled = false;
|
||||
```
|
||||
|
||||
#### 3. 缩放与方向控制
|
||||
```typescript
|
||||
// Boss怪物特殊处理
|
||||
let scale = -1; // 默认向左朝向
|
||||
if (is_boss) scale = 1; // Boss面向右侧
|
||||
```
|
||||
|
||||
**章节来源**
|
||||
- [Mon.ts](file://assets/script/game/hero/Mon.ts#L36-L60)
|
||||
|
||||
## hero_init方法深度解析
|
||||
|
||||
hero_init方法负责怪物的基础属性初始化和技能配置,是怪物能力系统的核心:
|
||||
|
||||
### 属性初始化流程
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant MI as Monster Instance
|
||||
participant HV as HeroViewComp
|
||||
participant HI as HeroInfo
|
||||
participant SS as SkillSet
|
||||
participant AS as Attrs System
|
||||
MI->>HV : 获取HeroView组件
|
||||
MI->>HI : 查询怪物配置
|
||||
MI->>HV : 设置基础属性
|
||||
MI->>MI : 计算强度倍率属性
|
||||
MI->>SS : 遍历技能列表
|
||||
SS-->>MI : 返回技能配置
|
||||
MI->>HV : 添加技能到技能列表
|
||||
MI->>AS : 初始化属性系统
|
||||
MI->>HV : 调用initAttrs()
|
||||
MI->>MI : 添加到实体组件
|
||||
```
|
||||
|
||||
**图表来源**
|
||||
- [Mon.ts](file://assets/script/game/hero/Mon.ts#L61-L108)
|
||||
|
||||
### 强度倍率动态调整机制
|
||||
|
||||
hero_init方法的核心特性是根据strengthMultiplier参数动态调整怪物属性:
|
||||
|
||||
#### 基础属性计算公式
|
||||
```typescript
|
||||
// 根据强度倍率调整基础属性
|
||||
const baseHp = Math.floor(hero.hp * strengthMultiplier);
|
||||
const baseAp = Math.floor(hero.ap * strengthMultiplier);
|
||||
const baseDef = Math.floor(hero.def * strengthMultiplier);
|
||||
```
|
||||
|
||||
#### 属性倍率影响范围
|
||||
| 属性类型 | 基础值 | 强度倍率影响 | 说明 |
|
||||
|----------|--------|--------------|------|
|
||||
| HP | hero.hp | × strengthMultiplier | 生命值线性增长 |
|
||||
| AP | hero.ap | × strengthMultiplier | 物理攻击力线性增长 |
|
||||
| DEF | hero.def | × strengthMultiplier | 物理防御力线性增长 |
|
||||
| MP | hero.mp | 不受影响 | 魔法值保持不变 |
|
||||
|
||||
### 技能系统初始化
|
||||
|
||||
#### 技能配置转换
|
||||
```typescript
|
||||
// 将HeroInfo中的技能ID转换为完整的技能配置
|
||||
for (let i = 0; i < hero.skills.length; i++) {
|
||||
let skill = {
|
||||
uuid: SkillSet[hero.skills[i]].uuid,
|
||||
cd_max: SkillSet[hero.skills[i]].cd,
|
||||
cost: SkillSet[hero.skills[i]].cost,
|
||||
cd: 0
|
||||
}
|
||||
hv.skills.push(skill);
|
||||
}
|
||||
```
|
||||
|
||||
#### 技能冷却系统
|
||||
每个技能初始化时:
|
||||
- `cd_max`: 技能最大冷却时间
|
||||
- `cost`: 技能消耗值
|
||||
- `cd`: 当前冷却计时器(初始为0)
|
||||
|
||||
**章节来源**
|
||||
- [Mon.ts](file://assets/script/game/hero/Mon.ts#L61-L108)
|
||||
|
||||
## 资源加载与预制体管理
|
||||
|
||||
### 资源加载机制
|
||||
|
||||
游戏采用Oops Framework的资源管理系统,通过oops.res.get方法加载预制体:
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
A[资源请求] --> B[oops.res.get]
|
||||
B --> C{资源是否存在?}
|
||||
C --> |是| D[返回预制体]
|
||||
C --> |否| E[抛出错误]
|
||||
D --> F[实例化预制体]
|
||||
F --> G[返回节点实例]
|
||||
E --> H[异常处理]
|
||||
```
|
||||
|
||||
**图表来源**
|
||||
- [Mon.ts](file://assets/script/game/hero/Mon.ts#L40-L42)
|
||||
|
||||
### 常见资源路径错误
|
||||
|
||||
#### 错误类型与解决方案
|
||||
|
||||
| 错误类型 | 症状 | 解决方案 |
|
||||
|----------|------|----------|
|
||||
| 路径不存在 | 预制体加载失败 | 检查HeroInfo配置中的path字段 |
|
||||
| 文件损坏 | 实例化时报错 | 重新导入预制体资源 |
|
||||
| 资源未打包 | 运行时找不到资源 | 确保资源已正确打包到构建中 |
|
||||
|
||||
### UUID越界检查
|
||||
|
||||
```typescript
|
||||
// UUID有效性验证
|
||||
let hero = HeroInfo[uuid];
|
||||
if (!hero) {
|
||||
console.error(`[Monster] 无效的怪物UUID: ${uuid}`);
|
||||
throw new Error(`怪物配置不存在: ${uuid}`);
|
||||
}
|
||||
```
|
||||
|
||||
**章节来源**
|
||||
- [Mon.ts](file://assets/script/game/hero/Mon.ts#L40-L42)
|
||||
- [heroSet.ts](file://assets/script/game/common/config/heroSet.ts#L70-L151)
|
||||
|
||||
## 场景节点挂载机制
|
||||
|
||||
### EntityLayer节点管理
|
||||
|
||||
EntityLayer作为场景中的物体层,负责管理所有动态物体的渲染顺序和生命周期:
|
||||
|
||||
```mermaid
|
||||
graph TB
|
||||
A[Scene] --> B[EntityLayer]
|
||||
B --> C[怪物节点]
|
||||
B --> D[技能特效]
|
||||
B --> E[UI元素]
|
||||
C --> F[Monster实例]
|
||||
F --> G[HeroViewComp]
|
||||
F --> H[MonModelComp]
|
||||
F --> I[BattleMoveComp]
|
||||
```
|
||||
|
||||
**图表来源**
|
||||
- [EntityLayer.ts](file://assets/script/game/map/view/map/layer/EntityLayer.ts#L18-L38)
|
||||
|
||||
### 挂载流程详解
|
||||
|
||||
#### 1. 场景引用获取
|
||||
```typescript
|
||||
var scene = smc.map.MapView.scene;
|
||||
```
|
||||
|
||||
#### 2. 父节点设置
|
||||
```typescript
|
||||
node.parent = scene.entityLayer!.node!;
|
||||
```
|
||||
|
||||
#### 3. 深度排序机制
|
||||
EntityLayer实现了定时器驱动的深度排序:
|
||||
```typescript
|
||||
private timer: Timer = new Timer(0.2);
|
||||
update(dt: number) {
|
||||
this.timer.update(dt);
|
||||
// 深度排序逻辑
|
||||
}
|
||||
```
|
||||
|
||||
**章节来源**
|
||||
- [EntityLayer.ts](file://assets/script/game/map/view/map/layer/EntityLayer.ts#L18-L38)
|
||||
- [Mon.ts](file://assets/script/game/hero/Mon.ts#L44-L45)
|
||||
|
||||
## 消息事件系统
|
||||
|
||||
### monster_load事件派发
|
||||
|
||||
游戏通过oops.message系统实现松耦合的消息通信:
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant M as Monster
|
||||
participant EM as Event Manager
|
||||
participant MC as MissionMonComp
|
||||
participant SM as Scene Manager
|
||||
M->>EM : dispatchEvent("monster_load", monster)
|
||||
EM->>MC : 通知怪物加载完成
|
||||
MC->>SM : 更新场景状态
|
||||
SM->>M : 可能的后续处理
|
||||
```
|
||||
|
||||
**图表来源**
|
||||
- [Mon.ts](file://assets/script/game/hero/Mon.ts#L56-L57)
|
||||
|
||||
### 事件监听与处理
|
||||
|
||||
#### MissionMonComp中的事件处理
|
||||
```typescript
|
||||
onLoad() {
|
||||
this.on(GameEvent.FightReady, this.fight_ready, this);
|
||||
this.on(GameEvent.NewWave, this.fight_ready, this);
|
||||
}
|
||||
```
|
||||
|
||||
#### 事件处理流程
|
||||
1. **FightReady事件**: 准备战斗阶段
|
||||
2. **NewWave事件**: 新一波怪物生成
|
||||
3. **monster_load事件**: 怪物实体加载完成
|
||||
|
||||
### 事件系统优势
|
||||
|
||||
| 优势 | 说明 | 应用场景 |
|
||||
|------|------|----------|
|
||||
| 松耦合 | 组件间无需直接依赖 | 怪物生成与场景管理 |
|
||||
| 可扩展 | 易于添加新的事件处理器 | 新增功能模块 |
|
||||
| 异步处理 | 支持异步事件流 | 怪物AI行为 |
|
||||
|
||||
**章节来源**
|
||||
- [Mon.ts](file://assets/script/game/hero/Mon.ts#L56-L57)
|
||||
- [MissionMonComp.ts](file://assets/script/game/map/MissionMonComp.ts#L34-L40)
|
||||
|
||||
## 异常处理与调试策略
|
||||
|
||||
### 常见异常类型
|
||||
|
||||
#### 1. 资源加载异常
|
||||
```typescript
|
||||
try {
|
||||
var prefab: Prefab = oops.res.get(path, Prefab)!;
|
||||
var node = instantiate(prefab);
|
||||
} catch (error) {
|
||||
console.error(`[Monster] 预制体加载失败: ${path}`, error);
|
||||
// 回退到默认预制体或显示错误界面
|
||||
}
|
||||
```
|
||||
|
||||
#### 2. UUID越界异常
|
||||
```typescript
|
||||
if (!HeroInfo[uuid]) {
|
||||
console.error(`[Monster] 未知的怪物UUID: ${uuid}`);
|
||||
// 使用默认怪物配置
|
||||
uuid = 5201; // 兽人战士作为默认值
|
||||
}
|
||||
```
|
||||
|
||||
#### 3. 节点层级缺失异常
|
||||
```typescript
|
||||
if (!scene.entityLayer || !scene.entityLayer.node) {
|
||||
console.error('[Monster] 场景实体层不存在');
|
||||
// 创建默认场景结构
|
||||
}
|
||||
```
|
||||
|
||||
### 调试策略
|
||||
|
||||
#### 1. 日志记录系统
|
||||
```typescript
|
||||
// 详细日志级别
|
||||
console.log("[Mon] mission_data.mon_num:", smc.vmdata.mission_data.mon_num);
|
||||
console.log("[Monster] 加载怪物:", uuid, "类型:", HeroInfo[uuid].type);
|
||||
```
|
||||
|
||||
#### 2. 断点调试技巧
|
||||
```typescript
|
||||
// 在关键位置设置断点
|
||||
if (process.env.NODE_ENV === 'development') {
|
||||
debugger;
|
||||
}
|
||||
```
|
||||
|
||||
#### 3. 性能监控
|
||||
```typescript
|
||||
// 性能计时器
|
||||
const startTime = performance.now();
|
||||
// ... 执行加载操作
|
||||
const endTime = performance.now();
|
||||
console.log(`[Monster] 加载耗时: ${endTime - startTime}ms`);
|
||||
```
|
||||
|
||||
### 异常恢复机制
|
||||
|
||||
#### 资源回退策略
|
||||
```typescript
|
||||
// 1. 尝试加载指定资源
|
||||
// 2. 如果失败,尝试加载备用资源
|
||||
// 3. 如果仍然失败,使用默认资源
|
||||
```
|
||||
|
||||
#### 配置验证
|
||||
```typescript
|
||||
// 验证HeroInfo配置完整性
|
||||
function validateHeroConfig(hero: heroInfo): boolean {
|
||||
return hero &&
|
||||
hero.hp > 0 &&
|
||||
hero.ap > 0 &&
|
||||
hero.def > 0 &&
|
||||
hero.skills.length > 0;
|
||||
}
|
||||
```
|
||||
|
||||
**章节来源**
|
||||
- [Mon.ts](file://assets/script/game/hero/Mon.ts#L36-L60)
|
||||
|
||||
## 实际应用示例
|
||||
|
||||
### 生成普通怪物
|
||||
|
||||
```typescript
|
||||
// 创建普通怪物实例
|
||||
let monster = ecs.getEntity<Monster>(Monster);
|
||||
let pos: Vec3 = v3(240, 100, 0);
|
||||
let scale = -1;
|
||||
|
||||
monster.load(
|
||||
pos, // 初始位置
|
||||
scale, // 缩放比例
|
||||
5201, // 兽人战士UUID
|
||||
false, // 非Boss
|
||||
false, // 非召唤
|
||||
1.0 // 强度倍率
|
||||
);
|
||||
```
|
||||
|
||||
### 生成Boss怪物
|
||||
|
||||
```typescript
|
||||
// 创建Boss怪物实例
|
||||
let boss = ecs.getEntity<Monster>(Monster);
|
||||
let bossPos: Vec3 = v3(400, 100, 0);
|
||||
|
||||
boss.load(
|
||||
bossPos, // Boss专用位置
|
||||
1, // 正向缩放
|
||||
5201, // 使用相同基础配置
|
||||
true, // Boss标志
|
||||
false, // 非召唤
|
||||
2.0 // 双倍强度
|
||||
);
|
||||
```
|
||||
|
||||
### MissionMonComp中的批量生成
|
||||
|
||||
```typescript
|
||||
// 在MissionMonComp中批量生成怪物
|
||||
private addMonster(
|
||||
uuid: number = 1001,
|
||||
i: number = 0,
|
||||
is_boss: boolean = false,
|
||||
is_call: boolean = false,
|
||||
lv: number = 1,
|
||||
strengthMultiplier: number = 1.0
|
||||
) {
|
||||
let mon = ecs.getEntity<Monster>(Monster);
|
||||
let scale = -1;
|
||||
let pos: Vec3 = v3(MonSet[i].pos);
|
||||
|
||||
mon.load(pos, scale, uuid, is_boss, is_call, strengthMultiplier);
|
||||
}
|
||||
```
|
||||
|
||||
### 强度倍率的实际效果
|
||||
|
||||
#### 基础属性对比表
|
||||
|
||||
| 属性类型 | 基础值(1.0倍) | 1.5倍 | 2.0倍 | 2.5倍 |
|
||||
|----------|---------------|-------|-------|-------|
|
||||
| HP | 25 | 37 | 50 | 62 |
|
||||
| AP | 5 | 7 | 10 | 12 |
|
||||
| DEF | 5 | 7 | 10 | 12 |
|
||||
| MP | 100 | 100 | 100 | 100 |
|
||||
|
||||
**章节来源**
|
||||
- [MissionMonComp.ts](file://assets/script/game/map/MissionMonComp.ts#L215-L239)
|
||||
- [heroSet.ts](file://assets/script/game/common/config/heroSet.ts#L120-L151)
|
||||
|
||||
## 总结
|
||||
|
||||
Monster类的load方法和hero_init方法构成了游戏怪物系统的核心基础设施,通过以下关键技术实现了灵活而强大的怪物生成机制:
|
||||
|
||||
### 核心技术特点
|
||||
|
||||
1. **动态资源加载**: 基于UUID的预制体动态加载,支持运行时配置
|
||||
2. **属性倍率系统**: 通过strengthMultiplier参数实现怪物强度的灵活调整
|
||||
3. **ECS架构模式**: 清晰的组件分离,便于维护和扩展
|
||||
4. **事件驱动通信**: 松耦合的消息系统,支持复杂的业务逻辑
|
||||
5. **异常处理机制**: 完善的错误处理和恢复策略
|
||||
|
||||
### 性能优化要点
|
||||
|
||||
- **预制体缓存**: 利用Oops Framework的资源管理系统
|
||||
- **延迟初始化**: 碰撞体的延迟启用减少初始化开销
|
||||
- **批量操作**: MissionMonComp中的批量怪物生成
|
||||
- **内存管理**: 及时清理不再使用的怪物实体
|
||||
|
||||
### 扩展建议
|
||||
|
||||
1. **配置系统增强**: 支持更多的怪物类型和属性变体
|
||||
2. **AI行为系统**: 集成更复杂的怪物AI逻辑
|
||||
3. **视觉效果**: 添加更多的怪物特效和动画
|
||||
4. **平衡性调整**: 提供更精细的难度调节机制
|
||||
|
||||
通过深入理解这些机制,开发者可以更好地维护和扩展游戏的怪物系统,为玩家提供更加丰富和有趣的游戏体验。
|
||||
270
.qoder/repowiki/zh/content/地图系统/怪物系统/怪物实体/怪物实体组件系统.md
Normal file
270
.qoder/repowiki/zh/content/地图系统/怪物系统/怪物实体/怪物实体组件系统.md
Normal file
@@ -0,0 +1,270 @@
|
||||
# 怪物实体组件系统
|
||||
|
||||
<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)
|
||||
- [BoxSet.ts](file://assets/script/game/common/config/BoxSet.ts)
|
||||
- [SingletonModuleComp.ts](file://assets/script/game/common/SingletonModuleComp.ts)
|
||||
- [Main.ts](file://assets/script/Main.ts)
|
||||
</cite>
|
||||
|
||||
## 目录
|
||||
1. [引言](#引言)
|
||||
2. [项目结构](#项目结构)
|
||||
3. [核心组件](#核心组件)
|
||||
4. [架构概述](#架构概述)
|
||||
5. [详细组件分析](#详细组件分析)
|
||||
6. [依赖分析](#依赖分析)
|
||||
7. [性能考虑](#性能考虑)
|
||||
8. [故障排除指南](#故障排除指南)
|
||||
9. [结论](#结论)
|
||||
|
||||
## 引言
|
||||
本文档详细说明了Cocos游戏项目中Monster实体的ECS(实体-组件-系统)机制,重点分析了在init方法中注册BattleMoveComp和MonModelComp组件的实现。文档深入解析了BattleMoveComp如何驱动怪物向左移动至目标X坐标(-800)的逻辑,结合BoxSet.MONSTER碰撞分组常量说明其在物理系统中的角色定义。同时阐述了MonModelComp作为数据容器的职责,包括属性重置机制与扩展字段设计原则,并提供开发示例和典型问题排查方法。
|
||||
|
||||
## 项目结构
|
||||
本项目采用基于功能模块的文件组织方式,核心游戏逻辑位于`assets/script/game`目录下,分为多个子模块如`hero`、`common`、`map`等。ECS相关组件和系统被组织在`common/ecs/position`路径下,体现了清晰的架构分层。
|
||||
|
||||
```mermaid
|
||||
graph TB
|
||||
subgraph "Assets"
|
||||
subgraph "Script"
|
||||
subgraph "Game"
|
||||
Hero[hero模块]
|
||||
Common[common模块]
|
||||
Map[map模块]
|
||||
Initialize[initialize模块]
|
||||
end
|
||||
Main[Main.ts]
|
||||
end
|
||||
Resources[resources]
|
||||
end
|
||||
Hero --> |包含| Monster[Monster实体]
|
||||
Common --> |包含| ECS[ECS系统]
|
||||
Common --> |包含| Config[配置文件]
|
||||
```
|
||||
|
||||
**Diagram sources**
|
||||
- [Mon.ts](file://assets/script/game/hero/Mon.ts)
|
||||
- [BattleMoveSystem.ts](file://assets/script/game/common/ecs/position/BattleMoveSystem.ts)
|
||||
- [BoxSet.ts](file://assets/script/game/common/config/BoxSet.ts)
|
||||
|
||||
**Section sources**
|
||||
- [Mon.ts](file://assets/script/game/hero/Mon.ts)
|
||||
- [Main.ts](file://assets/script/Main.ts)
|
||||
|
||||
## 核心组件
|
||||
Monster实体通过ECS架构实现了行为与数据的分离,其核心由BattleMoveComp(移动行为)和MonModelComp(数据模型)两个组件构成。这种设计模式使得组件可以独立开发、测试和复用,同时通过系统(System)统一管理组件间的交互逻辑。
|
||||
|
||||
**Section sources**
|
||||
- [Mon.ts](file://assets/script/game/hero/Mon.ts)
|
||||
- [BattleMoveComp.ts](file://assets/script/game/common/ecs/position/BattleMoveComp.ts)
|
||||
- [MonModelComp.ts](file://assets/script/game/hero/MonModelComp.ts)
|
||||
|
||||
## 架构概述
|
||||
游戏采用ECS(Entity-Component-System)架构模式,将游戏对象分解为实体(Entity)、组件(Component)和系统(System)三个核心概念。实体作为容器,持有多个组件;组件作为纯数据结构,存储特定功能的数据;系统则负责处理具有特定组件组合的实体,实现游戏逻辑。
|
||||
|
||||
```mermaid
|
||||
classDiagram
|
||||
class Entity {
|
||||
+addComponent(comp)
|
||||
+removeComponent(comp)
|
||||
+getComponent(type)
|
||||
}
|
||||
class Component {
|
||||
<<abstract>>
|
||||
+reset()
|
||||
}
|
||||
class System {
|
||||
<<abstract>>
|
||||
+filter()
|
||||
+update(entity)
|
||||
}
|
||||
class Monster {
|
||||
-BattleMoveComp
|
||||
-MonModelComp
|
||||
-TalComp
|
||||
}
|
||||
class BattleMoveComp {
|
||||
+direction : number
|
||||
+targetX : number
|
||||
+moving : boolean
|
||||
}
|
||||
class MonModelComp {
|
||||
<<data container>>
|
||||
}
|
||||
class BattleMoveSystem {
|
||||
+filter()
|
||||
+update(entity)
|
||||
}
|
||||
Entity <|-- Monster
|
||||
Component <|-- BattleMoveComp
|
||||
Component <|-- MonModelComp
|
||||
System <|-- BattleMoveSystem
|
||||
Monster --> BattleMoveComp
|
||||
Monster --> MonModelComp
|
||||
BattleMoveSystem ..> BattleMoveComp : processes
|
||||
BattleMoveSystem ..> HeroViewComp : interacts with
|
||||
```
|
||||
|
||||
**Diagram sources**
|
||||
- [Mon.ts](file://assets/script/game/hero/Mon.ts)
|
||||
- [BattleMoveComp.ts](file://assets/script/game/common/ecs/position/BattleMoveComp.ts)
|
||||
- [BattleMoveSystem.ts](file://assets/script/game/common/ecs/position/BattleMoveSystem.ts)
|
||||
|
||||
## 详细组件分析
|
||||
|
||||
### Monster实体初始化机制
|
||||
Monster实体在初始化时通过`addComponents`方法注册了BattleMoveComp、MonModelComp和TalComp三个组件。这一过程遵循ECS框架的组件注册规范,确保实体具备必要的数据和行为能力。
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant M as Monster
|
||||
participant ECS as ECS框架
|
||||
participant BMS as BattleMoveSystem
|
||||
M->>ECS : init()
|
||||
M->>ECS : addComponents(BattleMoveComp, MonModelComp, TalComp)
|
||||
ECS->>M : 返回组件实例引用
|
||||
M->>M : 设置HeroModel、HeroView、BattleMove成员变量
|
||||
M->>BMS : 系统检测到新实体
|
||||
BMS->>BMS : 将实体加入处理队列
|
||||
```
|
||||
|
||||
**Diagram sources**
|
||||
- [Mon.ts](file://assets/script/game/hero/Mon.ts)
|
||||
- [BattleMoveSystem.ts](file://assets/script/game/common/ecs/position/BattleMoveSystem.ts)
|
||||
|
||||
**Section sources**
|
||||
- [Mon.ts](file://assets/script/game/hero/Mon.ts#L15-L30)
|
||||
|
||||
### BattleMoveComp移动逻辑解析
|
||||
BattleMoveComp组件负责管理怪物的移动行为,其核心属性包括`direction`(移动方向)、`targetX`(目标X坐标)和`moving`(移动状态)。在Monster的`load`方法中,这些属性被初始化为向左移动至-800坐标。
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
Start([开始移动]) --> CheckState["检查游戏状态<br/>(play && !pause)"]
|
||||
CheckState --> |否| End([停止移动])
|
||||
CheckState --> |是| CheckStop["检查停止条件<br/>(is_stop, is_dead, isStun等)"]
|
||||
CheckStop --> |是| SetIdle["设置idle状态"] --> End
|
||||
CheckStop --> |否| CalculateDelta["计算位移增量<br/>delta = (SPEED/3) * dt * direction"]
|
||||
CalculateDelta --> CalculateNewX["计算新X坐标<br/>newX = currentX + delta"]
|
||||
CalculateNewX --> ValidatePos["验证位置有效性"]
|
||||
ValidatePos --> |有效| UpdatePos["更新节点位置"] --> SetMove["设置move状态"] --> End
|
||||
ValidatePos --> |无效| StopMoving["设置moving=false"] --> SetIdle --> End
|
||||
```
|
||||
|
||||
**Diagram sources**
|
||||
- [BattleMoveComp.ts](file://assets/script/game/common/ecs/position/BattleMoveComp.ts#L1-L15)
|
||||
- [BattleMoveSystem.ts](file://assets/script/game/common/ecs/position/BattleMoveSystem.ts#L50-L270)
|
||||
|
||||
**Section sources**
|
||||
- [Mon.ts](file://assets/script/game/hero/Mon.ts#L80-L90)
|
||||
- [BattleMoveComp.ts](file://assets/script/game/common/ecs/position/BattleMoveComp.ts)
|
||||
- [BattleMoveSystem.ts](file://assets/script/game/common/ecs/position/BattleMoveSystem.ts)
|
||||
|
||||
### BoxSet.MONSTER碰撞分组角色
|
||||
BoxSet.MONSTER常量定义了怪物实体在物理系统中的碰撞分组标识,值为2。该常量不仅用于物理碰撞检测,还作为阵营标识参与游戏逻辑判断,如敌我识别、技能作用范围等。
|
||||
|
||||
```mermaid
|
||||
erDiagram
|
||||
BOXSET ||--o{ MONSTER : "包含"
|
||||
BOXSET ||--o{ HERO : "包含"
|
||||
BOXSET ||--o{ SKILL : "包含"
|
||||
BOXSET {
|
||||
int MONSTER
|
||||
int HERO
|
||||
int SKILL_TAG
|
||||
int ATK_RANGE
|
||||
}
|
||||
MONSTER {
|
||||
string name
|
||||
int group = 2
|
||||
}
|
||||
HERO {
|
||||
string name
|
||||
int group = 4
|
||||
}
|
||||
SKILL {
|
||||
string name
|
||||
int tag = 8
|
||||
}
|
||||
```
|
||||
|
||||
**Diagram sources**
|
||||
- [BoxSet.ts](file://assets/script/game/common/config/BoxSet.ts#L5-L15)
|
||||
|
||||
**Section sources**
|
||||
- [BoxSet.ts](file://assets/script/game/common/config/BoxSet.ts)
|
||||
- [Mon.ts](file://assets/script/game/hero/Mon.ts#L75-L80)
|
||||
|
||||
### MonModelComp数据容器职责
|
||||
MonModelComp作为纯粹的数据容器组件,遵循ECS框架的组件设计原则。其主要职责是存储怪物的持久化数据,通过reset方法实现组件回收时的状态重置,保证组件在对象池中的可重用性。
|
||||
|
||||
```mermaid
|
||||
classDiagram
|
||||
class MonModelComp {
|
||||
<<data container>>
|
||||
+reset()
|
||||
}
|
||||
note right of MonModelComp
|
||||
作为数据容器,不包含业务逻辑
|
||||
所有数据操作由系统或其他组件完成
|
||||
reset方法确保组件回收时状态清零
|
||||
end note
|
||||
```
|
||||
|
||||
**Diagram sources**
|
||||
- [MonModelComp.ts](file://assets/script/game/hero/MonModelComp.ts#L1-L20)
|
||||
|
||||
**Section sources**
|
||||
- [MonModelComp.ts](file://assets/script/game/hero/MonModelComp.ts)
|
||||
|
||||
## 依赖分析
|
||||
Monster实体的组件系统存在明确的依赖关系,BattleMoveComp依赖于HeroViewComp的存在,因为移动逻辑需要操作视图节点的位置和状态。这种依赖关系通过BattleMoveSystem的filter方法声明,确保只有同时拥有这两个组件的实体才会被系统处理。
|
||||
|
||||
```mermaid
|
||||
graph LR
|
||||
A[BattleMoveSystem] --> B[BattleMoveComp]
|
||||
A --> C[HeroViewComp]
|
||||
D[Monster] --> B
|
||||
D --> E[MonModelComp]
|
||||
D --> F[TalComp]
|
||||
D --> C
|
||||
style A fill:#f9f,stroke:#333
|
||||
style B fill:#bbf,stroke:#333
|
||||
style C fill:#bbf,stroke:#333
|
||||
style D fill:#9f9,stroke:#333
|
||||
style E fill:#f96,stroke:#333
|
||||
style F fill:#f96,stroke:#333
|
||||
```
|
||||
|
||||
**Diagram sources**
|
||||
- [BattleMoveSystem.ts](file://assets/script/game/common/ecs/position/BattleMoveSystem.ts#L10-L15)
|
||||
- [Mon.ts](file://assets/script/game/hero/Mon.ts)
|
||||
|
||||
**Section sources**
|
||||
- [BattleMoveSystem.ts](file://assets/script/game/common/ecs/position/BattleMoveSystem.ts)
|
||||
- [Mon.ts](file://assets/script/game/hero/Mon.ts)
|
||||
|
||||
## 性能考虑
|
||||
ECS架构通过组件对象池机制有效减少了运行时的内存分配和垃圾回收压力。BattleMoveComp和MonModelComp的reset方法确保了组件在销毁时能够正确重置状态,使其可以安全地返回对象池供后续复用,从而提升整体性能表现。
|
||||
|
||||
## 故障排除指南
|
||||
### 组件注册遗漏
|
||||
当Monster实体缺少必要组件时,可能导致移动功能失效或数据丢失。检查`init`方法中的`addComponents`调用,确保所有必需组件都被正确注册。
|
||||
|
||||
**Section sources**
|
||||
- [Mon.ts](file://assets/script/game/hero/Mon.ts#L15-L30)
|
||||
|
||||
### 依赖顺序错误
|
||||
BattleMoveSystem要求实体同时拥有BattleMoveComp和HeroViewComp才能正常工作。如果组件添加顺序不当或遗漏HeroViewComp,系统将无法处理该实体。确保在调用`hero_init`方法前已完成所有必要组件的注册。
|
||||
|
||||
**Section sources**
|
||||
- [Mon.ts](file://assets/script/game/hero/Mon.ts#L100-L120)
|
||||
- [BattleMoveSystem.ts](file://assets/script/game/common/ecs/position/BattleMoveSystem.ts#L10-L15)
|
||||
|
||||
## 结论
|
||||
Monster实体的ECS实现展示了良好的架构设计,通过组件化分离了数据与行为,提高了代码的可维护性和可扩展性。BattleMoveComp的移动逻辑与BoxSet.MONSTER的碰撞分组协同工作,确保了怪物在游戏世界中的正确行为。开发者在扩展功能时应遵循相同的组件设计原则,确保系统的稳定性和一致性。
|
||||
Reference in New Issue
Block a user