需求与架构设计
需求(一个典型的动作 RPG 技能系统)
- 角色拥有 N 个技能,可装备/卸下,可冷却;
- 技能由按键触发,触发时进入"施法"流程(前摇 → 生效 → 后摇);
- 生效内容因技能而异:近战劈砍、投射物、范围伤害、治疗……;
- 全部数值(冷却、消耗、伤害)配在数据资产里,策划可改;
- 表现(蒙太奇、特效、音效)每个技能自己定。
设计时先分的两条线
规则线(C++,改动频率低):技能状态机(Ready → Casting → Cooldown)、冷却计时、施法流程的阶段推进、与动画事件的对接(Anim Notify)。
表现线(蓝图,改动频率高):播什么蒙太奇、特效挂在哪个插槽、音效混什么、镜头怎么动。
架构图
┌───────────────────────────────────────────────────┐
│ C++ 框架层 │
│ USkillComponent(角色持有) │
│ ├─ CurrentSkills: TArray<USkillAsset*> │
│ ├─ TryCastSkill(int Slot) → 状态机推进 │
│ └─ OnSkillCast / OnSkillCooldown(广播) │
│ │
│ USkillAsset(PrimaryDataAsset,纯数据) │
│ ├─ Cooldown / Cost / Damage 等数值 │
│ └─ SkillBlueprintClass(对应的表现蓝图) │
└───────────────────────────────────────────────────┘
┌───────────────────────────────────────────────────┐
│ 蓝图表象层 │
│ BP_SkillBase(AActor,技能表现基类) │
│ └─ OnCast_Start / OnCast_Hit / OnCast_End │
│ BP_Skill_Fireball 等具体技能(子蓝图) │
└───────────────────────────────────────────────────┘
为什么数据与表现分离
把"火球术的伤害 = 50"放在蓝图里,策划要改它就要打开蓝图、找到变量、改、编译、关掉——所有操作都在一个容易误碰的界面里。放在 DataAsset 里,改数就像改 Excel:双击、改 50 → 80、保存。
这一步分离是整套架构成立的基础:策划改数值、美术改表现、程序改框架,三者互不相见。
交互流程(一次施法)
玩家按 Q
→ USkillComponent::TryCastSkill(0)
→ 检查:冷却好了?蓝量够? → 生成/激活技能表现蓝图
→ 表现蓝图播前摇蒙太奇
→ Anim Notify "CastHit" → 伤害结算(C++)+ 特效(蓝图)
→ Anim Notify "CastEnd" → 进入冷却(C++ 计时)
注意Anim Notify 是动画与逻辑对接的标准桥梁——动画播到哪一帧生效,由美术在蒙太奇里加 Notify 决定,程序不用猜帧数。
本章小结
- 架构 = C++ 状态机与广播(USkillComponent)+ 数据资产(USkillAsset)+ 蓝图表现(BP_SkillBase)。
- 数据与表现分离是"三类角色互不挡道"的基础。
- 动画与逻辑用 Anim Notify 对接,生效帧由美术控制。
