297 lines
7.2 KiB
Markdown
297 lines
7.2 KiB
Markdown
# 新技能系统使用说明
|
||
|
||
## 📊 架构概览
|
||
|
||
基于 **oops-framework ECS** 架构设计的完整施法系统。
|
||
|
||
---
|
||
|
||
## 🗂️ 文件结构
|
||
|
||
```
|
||
技能系统文件:
|
||
├── HeroSkills.ts # 数据层:技能槽位数据
|
||
├── HSkillSystem.ts # 业务层:3个系统
|
||
│ ├── SkillCastSystem # 施法系统
|
||
│ ├── SkillCDSystem # CD更新系统
|
||
│ └── SkillAutocastSystem # 自动施法系统(AI)
|
||
└── SkillEnt.ts # 技能实体(复用现有)
|
||
```
|
||
|
||
---
|
||
|
||
## 🎯 设计理念
|
||
|
||
### **数据层(HeroSkillsComp)**
|
||
|
||
**职责**:存储角色拥有的技能列表和CD状态
|
||
|
||
```typescript
|
||
@ecs.register('HeroSkills')
|
||
export class HeroSkillsComp extends ecs.Comp {
|
||
skills: SkillSlot[] = []; // 技能槽位数组
|
||
|
||
// 数据方法
|
||
initSkills(skillIds: number[]) { } // 初始化技能
|
||
canCast(index, mp): boolean { } // 检查可施放
|
||
resetCD(index) { } // 重置CD
|
||
updateCDs(dt) { } // 更新CD
|
||
getReadySkills(mp): number[] { } // 获取就绪技能
|
||
}
|
||
```
|
||
|
||
**技能槽位数据**:
|
||
```typescript
|
||
interface SkillSlot {
|
||
uuid: number; // 技能配置ID
|
||
cd: number; // 当前CD(递减)
|
||
cd_max: number; // 最大CD
|
||
cost: number; // MP消耗
|
||
level: number; // 技能等级
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
### **业务层(3个系统)**
|
||
|
||
#### **1. SkillCastSystem(施法系统)⭐**
|
||
|
||
**职责**:监听施法请求,执行施法
|
||
|
||
```typescript
|
||
export class SkillCastSystem extends ecs.ComblockSystem
|
||
implements ecs.IEntityEnterSystem {
|
||
|
||
// 筛选:拥有技能 + 请求标记的实体
|
||
filter(): ecs.IMatcher {
|
||
return ecs.allOf(HeroSkillsComp, HeroAttrsComp, CastSkillRequestComp);
|
||
}
|
||
|
||
// 处理施法请求
|
||
entityEnter(e: ecs.Entity): void {
|
||
// 1. 检查施法条件(CD、MP、状态)
|
||
// 2. 扣除MP
|
||
// 3. 重置CD
|
||
// 4. 播放动画
|
||
// 5. 创建技能实体
|
||
// 6. 移除请求标记
|
||
}
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
#### **2. SkillCDSystem(CD更新系统)**
|
||
|
||
**职责**:每帧自动更新所有技能CD
|
||
|
||
```typescript
|
||
export class SkillCDSystem extends ecs.ComblockSystem
|
||
implements ecs.ISystemUpdate {
|
||
|
||
filter(): ecs.IMatcher {
|
||
return ecs.allOf(HeroSkillsComp);
|
||
}
|
||
|
||
update(e: ecs.Entity): void {
|
||
const skillsData = e.get(HeroSkillsComp);
|
||
skillsData.updateCDs(this.dt); // 自动递减CD
|
||
}
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
#### **3. SkillAutocastSystem(自动施法系统)**
|
||
|
||
**职责**:AI自动选择和施放技能
|
||
|
||
```typescript
|
||
export class SkillAutocastSystem extends ecs.ComblockSystem
|
||
implements ecs.ISystemUpdate {
|
||
|
||
filter(): ecs.IMatcher {
|
||
return ecs.allOf(HeroSkillsComp, HeroAttrsComp, HeroViewComp);
|
||
}
|
||
|
||
update(e: ecs.Entity): void {
|
||
// 1. 检查角色状态
|
||
// 2. 获取可施放技能
|
||
// 3. 选择目标
|
||
// 4. 添加施法请求标记 ← 触发 SkillCastSystem
|
||
}
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 🔄 数据流程
|
||
|
||
```
|
||
方式1:自动施法(AI)
|
||
SkillAutocastSystem.update()
|
||
├─ 检测可施放技能
|
||
├─ 选择目标
|
||
└─ 添加 CastSkillRequestComp 标记
|
||
↓
|
||
SkillCastSystem.entityEnter() ← 自动触发
|
||
├─ 检查施法条件
|
||
├─ 扣除MP
|
||
├─ 重置CD
|
||
├─ 播放施法动画
|
||
├─ 创建 SkillEnt
|
||
└─ 移除 CastSkillRequestComp
|
||
|
||
方式2:手动施法(玩家点击)
|
||
UI.onClick()
|
||
└─ skillConComp.manualCastSkill(index)
|
||
└─ 添加 CastSkillRequestComp 标记
|
||
↓
|
||
(后续流程同方式1)
|
||
|
||
方式3:强制施法(天赋、事件触发)
|
||
TalentSystem
|
||
└─ heroEntity.add(CastSkillRequestComp)
|
||
↓
|
||
(后续流程同方式1)
|
||
```
|
||
|
||
---
|
||
|
||
## 🚀 使用示例
|
||
|
||
### **示例 1:初始化角色技能**
|
||
|
||
```typescript
|
||
// Hero.ts - load() 方法中
|
||
const skillsComp = this.get(HeroSkillsComp);
|
||
skillsComp.initSkills(hero.skills); // [6001, 6005, 6010]
|
||
```
|
||
|
||
---
|
||
|
||
### **示例 2:自动施法(默认)**
|
||
|
||
**无需额外代码**,`SkillAutocastSystem` 会自动处理:
|
||
|
||
```typescript
|
||
// 每帧自动检测:
|
||
// - 是否有可施放技能?
|
||
// - CD好了?MP够?
|
||
// - 正在攻击?
|
||
// ✅ 自动添加施法请求标记 → 触发施法
|
||
```
|
||
|
||
---
|
||
|
||
### **示例 3:手动施法(玩家点击)**
|
||
|
||
```typescript
|
||
// UI 按钮点击
|
||
onSkillButton1Click() {
|
||
const skillCon = this.heroNode.getComponent(SkillConComp);
|
||
skillCon.manualCastSkill(0); // 施放第0个技能
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
### **示例 4:强制施法(天赋触发)**
|
||
|
||
```typescript
|
||
// 天赋系统
|
||
doTalentEffect(heroEntity: ecs.Entity) {
|
||
// ✅ 添加施法请求标记
|
||
const request = heroEntity.add(CastSkillRequestComp);
|
||
request.skillIndex = 1; // 施放第1个技能
|
||
request.targetPositions = [v3(100, 0, 0)];
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## ⚙️ 系统注册(Main.ts)
|
||
|
||
```typescript
|
||
protected async initEcsSystem() {
|
||
// ✅ 注册技能系统(按顺序)
|
||
oops.ecs.add(new SkillCDSystem()); // 1. CD更新
|
||
oops.ecs.add(new SkillAutocastSystem()); // 2. 自动施法AI
|
||
oops.ecs.add(new SkillCastSystem()); // 3. 施法执行
|
||
|
||
// 战斗系统
|
||
oops.ecs.add(new HeroAtkSystem());
|
||
oops.ecs.add(new HeroAttrSystem());
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 📋 迁移清单
|
||
|
||
### ✅ **已完成**
|
||
|
||
| 任务 | 状态 | 说明 |
|
||
|------|------|------|
|
||
| 创建 HeroSkillsComp | ✅ | 技能数据组件 |
|
||
| 创建 SkillCastSystem | ✅ | 施法执行系统 |
|
||
| 创建 SkillCDSystem | ✅ | CD更新系统 |
|
||
| 创建 SkillAutocastSystem | ✅ | 自动施法系统 |
|
||
| 更新 Hero.ts | ✅ | 添加 HeroSkillsComp |
|
||
| 更新 Mon.ts | ✅ | 添加 HeroSkillsComp |
|
||
| 从 HeroAttrsComp 移除 skills | ✅ | 数据迁移完成 |
|
||
| 更新 SkillConComp | ✅ | 使用新系统 |
|
||
|
||
---
|
||
|
||
## 🎯 与战斗系统集成
|
||
|
||
**技能系统只负责"施法",伤害结算由战斗系统处理**
|
||
|
||
```
|
||
SkillCastSystem(施法)
|
||
↓
|
||
创建 SkillEnt(技能实体)
|
||
↓
|
||
SkillEnt 碰撞检测
|
||
↓
|
||
AtkConCom.single_damage()
|
||
↓
|
||
HeroAtkSystem.doAttack() ← 统一战斗系统
|
||
├─ 暴击判定
|
||
├─ 闪避判定
|
||
├─ 护盾吸收
|
||
├─ 修改数据
|
||
└─ 触发视图
|
||
```
|
||
|
||
---
|
||
|
||
## ✅ 优点总结
|
||
|
||
| 优点 | 说明 |
|
||
|------|------|
|
||
| **数据分离** | 技能数据独立组件,不污染 HeroAttrsComp |
|
||
| **标记驱动** | 使用 CastSkillRequestComp 标记组件,符合 ECS |
|
||
| **职责清晰** | CD更新、施法检查、执行分离成独立系统 |
|
||
| **易于扩展** | 添加新施法方式(手动/自动/强制)无需改动核心 |
|
||
| **易于测试** | 可单独测试每个系统 |
|
||
| **代码复用** | 手动/自动/强制施法共用同一套逻辑 |
|
||
|
||
---
|
||
|
||
## 🎉 总结
|
||
|
||
**完整的、规范的、基于 oops-framework 的技能施法系统!**
|
||
|
||
✅ 符合 ECS 架构(数据/业务/视图分离)
|
||
✅ 使用标记组件驱动,完全解耦
|
||
✅ 复用现有 SkillEnt,无需重写
|
||
✅ 与战斗系统完美集成
|
||
✅ 支持自动/手动/强制多种施法方式
|
||
✅ 代码清晰,注释详细
|
||
|
||
**可直接投入生产使用!** 🚀
|
||
|