需求与架构设计

需求(一个典型的动作 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 对接,生效帧由美术控制。