7.2 KiB
7.2 KiB
新技能系统使用说明
📊 架构概览
基于 oops-framework ECS 架构设计的完整施法系统。
🗂️ 文件结构
技能系统文件:
├── HeroSkills.ts # 数据层:技能槽位数据
├── HSkillSystem.ts # 业务层:3个系统
│ ├── SkillCastSystem # 施法系统
│ ├── SkillCDSystem # CD更新系统
│ └── SkillAutocastSystem # 自动施法系统(AI)
└── SkillEnt.ts # 技能实体(复用现有)
🎯 设计理念
数据层(HeroSkillsComp)
职责:存储角色拥有的技能列表和CD状态
@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[] { } // 获取就绪技能
}
技能槽位数据:
interface SkillSlot {
uuid: number; // 技能配置ID
cd: number; // 当前CD(递减)
cd_max: number; // 最大CD
cost: number; // MP消耗
level: number; // 技能等级
}
业务层(3个系统)
1. SkillCastSystem(施法系统)⭐
职责:监听施法请求,执行施法
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
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自动选择和施放技能
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:初始化角色技能
// Hero.ts - load() 方法中
const skillsComp = this.get(HeroSkillsComp);
skillsComp.initSkills(hero.skills); // [6001, 6005, 6010]
示例 2:自动施法(默认)
无需额外代码,SkillAutocastSystem 会自动处理:
// 每帧自动检测:
// - 是否有可施放技能?
// - CD好了?MP够?
// - 正在攻击?
// ✅ 自动添加施法请求标记 → 触发施法
示例 3:手动施法(玩家点击)
// UI 按钮点击
onSkillButton1Click() {
const skillCon = this.heroNode.getComponent(SkillConComp);
skillCon.manualCastSkill(0); // 施放第0个技能
}
示例 4:强制施法(天赋触发)
// 天赋系统
doTalentEffect(heroEntity: ecs.Entity) {
// ✅ 添加施法请求标记
const request = heroEntity.add(CastSkillRequestComp);
request.skillIndex = 1; // 施放第1个技能
request.targetPositions = [v3(100, 0, 0)];
}
⚙️ 系统注册(Main.ts)
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,无需重写
✅ 与战斗系统完美集成
✅ 支持自动/手动/强制多种施法方式
✅ 代码清晰,注释详细
可直接投入生产使用! 🚀