Files
pixelheros/.qoder/repowiki/zh/content/技能执行机制/目标选择策略.md
2025-10-30 16:49:19 +08:00

474 lines
14 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 目标选择策略
<cite>
**本文档引用的文件**
- [SkillConComp.ts](file://assets/script/game/hero/SkillConComp.ts)
- [BoxSet.ts](file://assets/script/game/common/config/BoxSet.ts)
- [HeroViewComp.ts](file://assets/script/hero/HeroViewComp.ts)
- [BattleMoveSystem.ts](file://assets/script/game/common/ecs/position/BattleMoveSystem.ts)
- [heroSet.ts](file://assets/script/game/common/config/heroSet.ts)
- [Hero.ts](file://assets/script/hero/Hero.ts)
- [Mon.ts](file://assets/script/hero/Mon.ts)
</cite>
## 目录
1. [概述](#概述)
2. [项目结构](#项目结构)
3. [核心组件](#核心组件)
4. [架构概览](#架构概览)
5. [详细组件分析](#详细组件分析)
6. [依赖关系分析](#依赖关系分析)
7. [性能考虑](#性能考虑)
8. [故障排除指南](#故障排除指南)
9. [结论](#结论)
## 概述
本文档深入分析了《英雄传说》游戏中目标选择算法的核心实现,重点关注`selectTargets`方法的策略设计。该算法采用智能的目标分配机制,确保战斗系统的公平性和策略性。
目标选择算法的核心特点:
- **优先级策略**:第一个目标总是最前排的单位
- **随机性机制**:后续目标通过随机选择确保多样性
- **重复允许**:支持同一目标被多次选中
- **边界处理**:当无可用目标时返回默认位置
- **阵营感知**基于FacSet判断左右方向
## 项目结构
```mermaid
graph TB
subgraph "技能系统"
SkillConComp["SkillConComp<br/>技能控制器"]
SkillEnt["SkillEnt<br/>技能实体"]
end
subgraph "阵营系统"
FacSet["FacSet<br/>阵营枚举"]
HeroViewComp["HeroViewComp<br/>英雄视图组件"]
end
subgraph "ECS系统"
ECS["ECS框架"]
BattleMoveSystem["BattleMoveSystem<br/>战斗移动系统"]
end
subgraph "目标检测"
check_target["check_target()<br/>目标检测"]
get_front["get_front()<br/>前排检测"]
selectTargets["selectTargets()<br/>目标选择"]
end
SkillConComp --> check_target
SkillConComp --> get_front
SkillConComp --> selectTargets
check_target --> ECS
get_front --> ECS
BattleMoveSystem --> ECS
```
**图表来源**
- [SkillConComp.ts](file://assets/script/game/hero/SkillConComp.ts#L109-L122)
- [BattleMoveSystem.ts](file://assets/script/game/common/ecs/position/BattleMoveSystem.ts#L165-L200)
**章节来源**
- [SkillConComp.ts](file://assets/script/game/hero/SkillConComp.ts#L1-L177)
- [BoxSet.ts](file://assets/script/game/common/config/BoxSet.ts#L1-L109)
## 核心组件
### SkillConComp - 技能控制器
`SkillConComp`是目标选择算法的核心控制器,负责协调整个目标选择流程。该组件继承自`CCComp`实现了ECS注册功能。
主要职责:
- **技能施放管理**:控制技能的触发时机和目标选择
- **目标选择协调**:调用`selectTargets`方法获取目标坐标
- **异常处理**:确保节点有效性检查和资源清理
### FacSet - 阵营系统
`FacSet`定义了游戏中的阵营概念,是目标选择算法的重要输入参数。
阵营常量:
- `HERO = 0`:英雄阵营,位于战场左侧
- `MON = 1`:怪物阵营,位于战场右侧
阵营决定了目标选择的方向性逻辑,英雄会选择右侧的怪物作为目标,而怪物会选择左侧的英雄作为目标。
**章节来源**
- [SkillConComp.ts](file://assets/script/game/hero/SkillConComp.ts#L1-L50)
- [BoxSet.ts](file://assets/script/game/common/config/BoxSet.ts#L48-L50)
## 架构概览
```mermaid
sequenceDiagram
participant SkillCon as "SkillConComp"
participant ECS as "ECS查询系统"
participant BattleMove as "BattleMoveSystem"
participant HeroView as "HeroViewComp"
SkillCon->>SkillCon : check_target()
SkillCon->>ECS : ecs.query(allOf(MonModelComp))
ECS-->>SkillCon : 目标实体列表
alt 有可用目标
SkillCon->>SkillCon : get_front(entities)
SkillCon->>SkillCon : selectTargets(t_num)
SkillCon->>SkillCon : 返回目标坐标数组
else 无可用目标
SkillCon->>SkillCon : 返回默认位置
end
Note over SkillCon,BattleMove : 目标选择完成,准备施放技能
```
**图表来源**
- [SkillConComp.ts](file://assets/script/game/hero/SkillConComp.ts#L109-L154)
- [BattleMoveSystem.ts](file://assets/script/game/common/ecs/position/BattleMoveSystem.ts#L198-L235)
## 详细组件分析
### selectTargets 方法详解
`selectTargets`方法是目标选择算法的核心实现,采用了精心设计的策略来确保战斗的公平性和策略性。
#### 算法流程
```mermaid
flowchart TD
Start([开始目标选择]) --> CheckEntities["检查可用实体"]
CheckEntities --> HasEntities{"是否有可用实体?"}
HasEntities --> |否| DefaultPos["返回默认位置"]
DefaultPos --> CloneDefault["克隆默认位置"]
CloneDefault --> ReturnDefault["返回t_num个默认位置"]
HasEntities --> |是| GetFront["获取最前排目标"]
GetFront --> PushFront["添加最前排坐标到targets"]
PushFront --> LoopTargets["循环添加后续目标"]
LoopTargets --> RandomSelect["随机选择实体"]
RandomSelect --> AddRandom["添加随机坐标到targets"]
AddRandom --> MoreTargets{"还有更多目标?"}
MoreTargets --> |是| LoopTargets
MoreTargets --> |否| ReturnTargets["返回目标坐标数组"]
ReturnDefault --> End([结束])
ReturnTargets --> End
```
**图表来源**
- [SkillConComp.ts](file://assets/script/game/hero/SkillConComp.ts#L128-L154)
#### 第一个目标:最前排单位
算法的第一个目标总是最前排的单位,这是基于以下设计原则:
1. **战略优先级**:最前排单位通常是敌方的主力或关键目标
2. **视觉反馈**:玩家能够直观看到技能的主要目标
3. **战斗节奏**:确保技能施放具有明确的战略意义
**实现细节**
- 使用`get_front`方法确定最前排位置
- 根据阵营方向选择最小或最大X坐标
- 确保第一个目标始终是最接近施法者的前排单位
#### 后续目标:随机选择机制
从第二个目标开始,算法采用随机选择机制:
1. **随机性保证**:每个目标都有平等的选择机会
2. **重复允许**:同一个实体可能被多次选中
3. **性能优化**:避免复杂的排序和去重操作
**实现原理**
- 使用`Math.random()`生成随机索引
- 直接从实体列表中选择对应实体
- 确保算法复杂度为O(n)其中n为目标数量
#### 默认位置处理
当没有可用目标时,算法返回预定义的默认位置:
```typescript
const defaultPos = this.HeroView.fac === FacSet.HERO ? v3(400, 0, 0) : v3(-400, 0, 0);
```
**设计意图**
- **战场定位**:默认位置位于战场边缘,不影响战斗区域
- **视觉平衡**:确保技能效果在视觉上仍然有意义
- **战术灵活性**:为玩家提供策略选择的空间
**章节来源**
- [SkillConComp.ts](file://assets/script/game/hero/SkillConComp.ts#L128-L154)
### check_target 方法分析
`check_target`方法负责根据阵营确定目标实体集合:
```mermaid
classDiagram
class SkillConComp {
+HeroView : any
+check_target() Entity[]
+get_front(entities) Vec3
+selectTargets(t_num) Vec3[]
}
class FacSet {
<<enumeration>>
HERO = 0
MON = 1
}
class ECS {
+query(filter) Entity[]
+allOf(component) Filter
}
SkillConComp --> FacSet : "使用"
SkillConComp --> ECS : "查询"
note for SkillConComp "根据阵营决定查询英雄还是怪物"
note for FacSet "定义阵营常量"
note for ECS "提供实体查询功能"
```
**图表来源**
- [SkillConComp.ts](file://assets/script/game/hero/SkillConComp.ts#L109-L115)
- [BoxSet.ts](file://assets/script/game/common/config/BoxSet.ts#L48-L50)
**实现逻辑**
- 英雄阵营FacSet.HERO查询怪物实体MonModelComp
- 怪物阵营FacSet.MON查询英雄实体HeroModelComp
这种设计确保了目标选择的阵营对立性,符合游戏的战斗机制。
**章节来源**
- [SkillConComp.ts](file://assets/script/game/hero/SkillConComp.ts#L109-L115)
### get_front 方法详解
`get_front`方法实现了前排单位的智能识别:
#### X坐标比较逻辑
```mermaid
flowchart LR
subgraph "英雄阵营 (FacSet.HERO)"
MinX["Math.min(...entities.map(e => e.get(HeroViewComp).node.position.x))"]
MinX --> Leftmost["找到最左侧的X坐标"]
end
subgraph "怪物阵营 (FacSet.MON)"
MaxX["Math.max(...entities.map(e => e.get(HeroViewComp).node.position.x))"]
MaxX --> Rightmost["找到最右侧的X坐标"]
end
Leftmost --> KeyEntity["查找对应实体"]
Rightmost --> KeyEntity
KeyEntity --> FrontPos["返回前排坐标"]
```
**图表来源**
- [SkillConComp.ts](file://assets/script/game/hero/SkillConComp.ts#L116-L122)
#### 方向性判断
算法根据阵营自动判断左右方向:
1. **英雄阵营**寻找最小X坐标即最左侧的单位
2. **怪物阵营**寻找最大X坐标即最右侧的单位
这种设计符合战场布局的直觉认知,英雄在左侧,怪物在右侧。
#### 实体匹配过程
```typescript
let keyPos = this.HeroView.fac == FacSet.HERO ?
Math.min(...entities.map(e => e.get(HeroViewComp).node.position.x)) :
Math.max(...entities.map(e => e.get(HeroViewComp).node.position.x));
let keyEntity = entities.find(e => e.get(HeroViewComp).node.position.x === keyPos);
return keyEntity.get(HeroViewComp).node.position;
```
这个过程确保了:
- 正确的前排单位被识别
- 坐标信息准确返回
- 异常情况下的稳定性
**章节来源**
- [SkillConComp.ts](file://assets/script/game/hero/SkillConComp.ts#L116-L122)
### ECS查询与坐标比较整合
目标选择算法与ECS系统的深度集成体现在以下几个方面
#### 查询优化
```mermaid
graph TD
A[ECS查询] --> B[allOf过滤]
B --> C[实体列表]
C --> D[坐标提取]
D --> E[X坐标数组]
E --> F[Math.min/max计算]
F --> G[前排坐标]
G --> H[实体匹配]
H --> I[最终目标]
style A fill:#e1f5fe
style F fill:#f3e5f5
style I fill:#e8f5e8
```
**图表来源**
- [BattleMoveSystem.ts](file://assets/script/game/common/ecs/position/BattleMoveSystem.ts#L198-L235)
#### 性能考量
1. **批量查询**:一次性获取所有符合条件的实体
2. **延迟计算**:只在需要时进行坐标比较
3. **内存优化**:避免不必要的对象创建
#### 异常处理
算法包含了多层异常保护:
1. **空实体检查**:防止空列表访问
2. **坐标有效性验证**:确保坐标数据正确
3. **实体状态检查**:排除无效或死亡的实体
**章节来源**
- [BattleMoveSystem.ts](file://assets/script/game/common/ecs/position/BattleMoveSystem.ts#L198-L235)
## 依赖关系分析
```mermaid
graph LR
subgraph "外部依赖"
ECS["ECS框架"]
Vec3["Vec3类"]
FacSet["FacSet枚举"]
end
subgraph "内部组件"
SkillConComp["SkillConComp"]
HeroViewComp["HeroViewComp"]
BattleMoveSystem["BattleMoveSystem"]
end
subgraph "配置文件"
BoxSet["BoxSet.ts"]
heroSet["heroSet.ts"]
end
SkillConComp --> ECS
SkillConComp --> Vec3
SkillConComp --> FacSet
SkillConComp --> HeroViewComp
BattleMoveSystem --> ECS
BattleMoveSystem --> HeroViewComp
BoxSet --> FacSet
heroSet --> HeroViewComp
style SkillConComp fill:#ffeb3b
style ECS fill:#2196f3
style FacSet fill:#4caf50
```
**图表来源**
- [SkillConComp.ts](file://assets/script/game/hero/SkillConComp.ts#L1-L15)
- [BoxSet.ts](file://assets/script/game/common/config/BoxSet.ts#L1-L10)
### 核心依赖关系
1. **ECS框架依赖**`ecs.query()`用于实体查询
2. **数学运算依赖**`Math.min()``Math.max()`用于坐标比较
3. **类型系统依赖**`Vec3``Entity`类型定义
4. **配置系统依赖**`FacSet`提供阵营常量
### 松耦合设计
算法采用松耦合设计,便于维护和扩展:
- **接口隔离**通过ECS查询接口与具体实体解耦
- **配置驱动**:阵营逻辑通过配置文件管理
- **模块化组织**:各功能模块职责单一
**章节来源**
- [SkillConComp.ts](file://assets/script/game/hero/SkillConComp.ts#L1-L177)
- [BattleMoveSystem.ts](file://assets/script/game/common/ecs/position/BattleMoveSystem.ts#L1-L270)
## 性能考虑
### 时间复杂度分析
目标选择算法的时间复杂度为O(n)其中n为目标数量
1. **ECS查询**O(m)m为实体总数
2. **坐标提取**O(m)
3. **前排计算**O(m)
4. **目标生成**O(n)
### 空间复杂度分析
空间复杂度为O(m+n),主要用于存储实体列表和目标坐标:
1. **实体缓存**:存储查询结果
2. **目标数组**:存储最终目标坐标
3. **临时变量**:坐标计算过程中的中间值
### 性能优化策略
1. **查询复用**:一次查询结果供多个目标选择使用
2. **延迟计算**:只在需要时进行坐标比较
3. **内存池化**重用Vec3对象减少GC压力
## 故障排除指南
### 常见异常情况
#### 空实体列表
**问题描述**:当没有可用目标时,算法返回默认位置。
**解决方案**
- 检查ECS查询条件是否正确
- 验证实体是否正确添加到场景中
- 确认实体组件是否完整
#### 坐标计算错误
**问题描述**:前排单位识别不准确。
**解决方案**
- 验证`HeroViewComp`组件是否正确挂载
- 检查实体位置是否正确初始化
- 确认坐标系统的一致性
#### 随机选择偏差
**问题描述**:随机选择结果不均匀。
**解决方案**
- 检查`Math.random()`的分布特性
- 验证实体列表的完整性
- 确认索引计算的正确性
### 调试技巧
1. **日志记录**:在关键步骤添加调试信息
2. **可视化**:绘制目标选择路径
3. **单元测试**:为每个方法编写测试用例
**章节来源**
- [SkillConComp.ts](file://assets/script/game/hero/SkillConComp.ts#L128-L154)
## 结论
目标选择算法展现了优秀的工程设计原则:
### 设计优势
1. **清晰的职责分离**:每个方法专注于特定功能
2. **灵活的扩展性**:易于适应新的需求变化
3. **稳定的性能表现**O(n)时间复杂度确保高效运行
4. **健壮的异常处理**:多层次保护机制
### 战术价值
算法的设计充分考虑了战斗策略的需求:
- **优先级策略**:确保关键目标优先被选中
- **随机性机制**:增加战斗的不确定性和趣味性
- **边界处理**:优雅处理异常情况
- **阵营感知**:符合游戏世界的逻辑设定
### 未来改进方向
1. **智能预测**:基于历史数据预测目标偏好
2. **动态权重**:根据战斗状态调整目标选择权重
3. **机器学习**利用AI技术优化目标选择策略
4. **实时反馈**:提供更直观的目标选择反馈
该算法为游戏战斗系统提供了坚实的基础,其设计理念和实现方式值得在类似项目中借鉴和应用。