12 KiB
技能基座重构 — 迁移计划
基于 spec: docs/superpowers/specs/2026-05-22-skill-template-refactor-design.md
迁移原则
- 每个步骤是最小功能单元,完成后可独立验证
- 使用兼容层过渡:新旧接口并存期间,代码同时读取两个位置
- 验证方式:每步完成后运行游戏,确认技能系统行为不变
Phase 1:类型定义(零风险,不改行为)
Step 1.1:新增 SkillTemplate/SkillDefaults/HeroOverrides 接口
文件:SkillSet.ts
改动:
- 在现有
SkillConfig下方新增SkillTemplate、SkillDefaults、HeroOverrides接口定义 - 新增
TriggerSkillConf接口 - 更新
BuffConf:新增attr字段,保留旧buff字段(标注@deprecated) - 不删除任何旧代码
验证:编译通过,游戏行为不变(新接口尚未被使用)
Step 1.2:新增 resolveSkillParams 工具函数
文件:SkillSet.ts 或新建 SkillResolve.ts
改动:
export function resolveSkillParams(
template: SkillTemplate,
heroSkill?: HSkillInfo,
triggerConf?: TriggerSkillConf
): { kind: SkillKind } & SkillDefaults {
return {
kind: template.kind,
...template.defaults,
...heroSkill?.overrides,
...triggerConf?.overrides,
};
}
验证:编译通过,写一个简单的测试用例验证三级覆盖逻辑
Phase 2:兼容层(数据迁移的安全网)
Step 2.1:新增兼容读取函数
文件:SkillSet.ts
改动:新增辅助函数,从旧 SkillConfig 构造 SkillTemplate + SkillDefaults:
/** 从旧 SkillConfig 提取 defaults 字段(过渡期使用) */
export function legacyDefaults(config: SkillConfig): SkillDefaults {
return {
TGroup: config.TGroup,
ap: config.ap,
t_num: 1, // 旧配置无此字段,使用默认值
hit_count: config.hit_count,
hitcd: config.hitcd,
crt: config.crt,
frz: config.frz,
bck: config.bck,
buffs: config.buffs,
};
}
/** 从旧 SkillConfig 提取 template 字段 */
export function legacyTemplate(config: SkillConfig): SkillTemplate {
return {
uuid: config.uuid,
name: config.name,
sp_name: config.sp_name,
icon: config.icon,
kind: config.kind ?? SkillKind.Damage,
act: config.act,
readyAnm: config.readyAnm,
endAnm: config.endAnm,
EAnm: config.EAnm,
DAnm: config.DAnm,
ready: config.ready,
IType: config.IType,
RType: config.RType,
EType: config.EType,
speed: config.speed,
DTType: config.DTType,
with: config.with,
bezier_start_y: config.bezier_start_y,
bezier_mid_y: config.bezier_mid_y,
bezier_arc: config.bezier_arc,
time: config.time,
defaults: legacyDefaults(config),
info: config.info,
};
}
验证:编译通过,可写测试验证提取结果与原配置一致
Phase 3:数据迁移(逐个技能类型)
Step 3.1:迁移 buff 技能数据(6401-6406, 6501)
文件:SkillSet.ts
改动:将 6401-6406、6501 从 SkillConfig 格式改为 SkillTemplate 格式:
- 顶层数值字段 →
defaults - 显式添加
kind: SkillKind.Support buffs中的buff:→attr:
存储方式:新增 BuffSkillTemplates: Record<number, SkillTemplate>,旧数据保留在 SkillSet 中
验证:游戏运行,确认卡牌释放 buff 技能效果不变
Step 3.2:迁移辅助技能数据(6301-6305)
文件:SkillSet.ts
改动:将护盾/治疗技能从旧格式改为 SkillTemplate 格式
- 护盾类:
kind: SkillKind.Shield - 治疗类:
kind: SkillKind.Heal
存储方式:新增 SupportSkillTemplates: Record<number, SkillTemplate>,旧数据保留
验证:游戏运行,确认护盾和治疗技能效果不变
Step 3.3:迁移必杀技数据(6104-6107)
文件:SkillSet.ts
改动:将必杀技从旧格式改为 SkillTemplate 格式
- 全部
kind: SkillKind.Damage crt/frz移入 defaults
验证:游戏运行,确认必杀技伤害和特效不变
Step 3.4:迁移基础攻击技能数据(6001-6103)
文件:SkillSet.ts
改动:将所有攻击技能从旧格式改为 SkillTemplate 格式
- 全部
kind: SkillKind.Damage
验证:游戏运行,确认所有英雄和怪物的普攻、远程攻击正常
Step 3.5:合并为新表
文件:SkillSet.ts
改动:将分散的 BuffSkillTemplates、SupportSkillTemplates 等合并为一个:
export const SkillTemplates: Record<number, SkillTemplate> = { ... 所有已迁移的技能 ... }
验证:通过所有新模板创建技能,确认与旧 SkillSet 行为一致
Phase 4:消费者适配(逐文件)
Step 4.1:适配 Skill.ts(技能实体创建)
文件:assets/script/game/skill/Skill.ts
改动:
skill.load()参数从config: SkillConfig改为template: SkillTemplate- 内部读取
template.sp_name(表现字段,未变) - 传递给 SMoveSystem/STimeComp 的 config 改为 template
ap/crt/frz/hit_count从template.defaults读取(通过兼容函数)
关键行:
- ~112:
config.sp_name→template.sp_name - ~153:
config.EType→template.EType - ~181:
config.RType→template.RType - ~183-185:
config.bezier_*→template.bezier_* - ~195:
config.time→template.time - ~196:
config.hitcd→template.hitcd - ~211-214:
config.crt/config.frz/config.ap/config.hit_count→template.defaults.*
验证:释放各种技能,确认弹道动画和伤害数值正确
Step 4.2:适配 SMoveSystem.ts(技能移动)
文件:assets/script/game/skill/SMoveSystem.ts
改动:
- 类型引用
SkillConfig→SkillTemplate - 读取的字段(speed、RType、EType、bezier_*)均在模板顶层,无需改逻辑
验证:确认弹道轨迹(直线/贝塞尔/固定)正常
Step 4.3:适配 STimeComp.ts(技能时间控制)
文件:assets/script/game/skill/STimeComp.ts
改动:
- 类型引用
SkillConfig→SkillTemplate - 只读
EType(模板顶层字段),逻辑不变
验证:确认技能持续时间、碰撞消失逻辑正常
Step 4.4:适配 SkillView.ts(技能视图)
文件:assets/script/game/skill/SkillView.ts
改动:
- 类型引用
SkillConfig→SkillTemplate - 只读
EType(模板顶层字段),逻辑不变
验证:确认技能特效显示正常
Step 4.5:适配 HeroViewComp.ts(命中动画)
文件:assets/script/game/hero/HeroViewComp.ts
改动:
- ~507:
SConf?.DAnm→template?.DAnm(字段仍在顶层,只改引用名)
验证:确认受击动画(普通/冰/火/风)显示正确
Step 4.6:适配 SCastSystem.ts(施法系统 — 核心)
文件:assets/script/game/hero/SCastSystem.ts
改动:
- 引入
resolveSkillParams()和legacyTemplate() forceCastSkill()中SkillSet[s_uuid]→SkillTemplates[s_uuid],通过resolveSkillParams(template, undefined, undefined)获取参数applyFriendlySkillEffects()改为接收 resolved paramsapplyActualFriendlyEffect()中:config.buffs→resolved.buffsbuffConf.buff→buffConf.attr(同时兼容旧buff字段)
- 伤害技能路径中
config.ap/config.crt/config.frz/config.hit_count→ 从 resolved params 读取 config.TGroup→resolved.TGroupconfig.kind→template.kind(模板固定)
验证:
- 英雄普攻伤害正确
- 必杀技伤害和特效正确
- 护盾/治疗/buff 效果正确
- 卡牌技能效果正确
Step 4.7:适配 HeroAtkSystem.ts(伤害系统)
文件:assets/script/game/hero/HeroAtkSystem.ts
改动:
- ~292:
sConf.ap→ 从 resolved defaults 读取 - ~221:
reviveSkillConf.ap→ 从 resolved defaults 读取 - ~236:
reviveSkillConf.readyAnm→ 从 template 读取(模板顶层字段)
验证:
- 英雄伤害数值正确
- 复活技能恢复血量正确
Step 4.8:适配 SkillTriggerHelper.ts(触发技能)
文件:assets/script/game/hero/SkillTriggerHelper.ts
改动:
- 触发技能时,将
triggerConf.overrides传递给resolveSkillParams()
验证:确认受击触发护盾、普攻触发治疗等触发技能正常
Step 4.9:适配 Hero.ts + Mon.ts(初始化)
文件:Hero.ts、Mon.ts
改动:
- 英雄/怪物初始化时,将
heroInfo.atking/atked等配置传入 HeroAttrsComp - HeroAttrsComp 中的类型同步更新为
TriggerSkillConf[]
验证:英雄和怪物的触发技能正常工作
Step 4.10:适配显示层文件
文件:CardComp.ts、IBoxComp.ts、TooltipCom.ts、SIconComp.ts、SkillBoxComp.ts、HlistComp.ts
改动:
- 仅引用名变更(
SkillConfig→SkillTemplate) - 读取的字段(name、icon、IType、info)均在模板顶层,无需改逻辑
验证:卡牌显示、信息面板、技能图标显示正常
Phase 5:角色定制(新功能启用)
Step 5.1:更新 heroSet.ts 触发配置类型
文件:heroSet.ts
改动:
atking/atked等类型从{s_uuid, t_num}内联 →TriggerSkillConf[]- 向后兼容:
overrides可选,旧配置无需修改
验证:编译通过,游戏行为不变(尚未添加 overrides)
Step 5.2:为首个角色添加 overrides
文件:heroSet.ts
改动:选一个典型角色(如盾骑士 5002)作为试点,为其触发技能添加 overrides:
5002: {
...,
atked: [{ s_uuid: 6301, t_num: 2,
overrides: { TGroup: TGroup.Team, ap: 2, t_num: 5, hit_count: 3 }
}],
},
验证:盾骑士受击后给全队加盾,而非只给自己加。对比修改前后行为确认覆盖生效
Step 5.3:逐步为其他角色添加 overrides
文件:heroSet.ts
改动:逐个角色添加 overrides,每添加一个验证一次
验证:每个角色的技能行为符合设计意图
Phase 6:清理
Step 6.1:删除旧 SkillConfig 接口和 SkillSet 数据
文件:SkillSet.ts
改动:
- 删除
SkillConfig接口 - 删除旧
SkillSet数据(已被SkillTemplates替代) - 删除
legacyTemplate()/legacyDefaults()兼容函数 SkillTemplates重命名回SkillSet(或保持新名,全局替换引用)
验证:全面回归测试
Step 6.2:BuffConf 清理
文件:SkillSet.ts、SCastSystem.ts
改动:
- 删除
BuffConf.buff字段,只保留attr - 所有配置数据中
buff:→attr:
验证:buff 技能效果正确
Step 6.3:删除 kind 回退逻辑
文件:SCastSystem.ts
改动:
- 移除
config.kind ?? SkillKind.Damage和config.kind ?? SkillKind.Support回退 - 全部使用
template.kind
验证:所有技能类型判定正确
验证检查清单
每个 Step 完成后,运行以下检查:
| 检查项 | 方法 |
|---|---|
| 编译通过 | 无 TypeScript 错误 |
| 普攻正常 | 放置近战/远程英雄,观察普攻弹道和伤害 |
| 必杀技正常 | 触发必杀技,确认特效和伤害 |
| 护盾正常 | 触发护盾技能,确认护盾层数和显示 |
| 治疗正常 | 触发治疗技能,确认血量恢复 |
| Buff 正常 | 触发 buff 技能,确认属性变化 |
| 卡牌技能正常 | 使用卡牌释放各种技能 |
| 触发技能正常 | 受击/攻击/死亡/开始触发链正常 |
| 怪物行为正常 | 怪物攻击和技能释放正常 |
| 无控制台报错 | 检查浏览器控制台无 JS 错误 |