Files
BlueRoseNote/RPGGameplayAbility重构文档.md

910 lines
30 KiB
Markdown
Raw Normal View History

2026-05-30 22:33:48 +08:00
---
tags:
- GAS
- UE5
- 架构
- 重构
- 插件
date: 2026-05-30
project: MusicFighterGame
plugin: RPGGameplayAbility
status: 设计阶段
---
# RPGGameplayAbility 插件重构文档
## 概述
本文档基于对以下三个 UE5 项目的深度研究,分析其 GameplayAbilitySystem (GAS) 架构、插件设计和技术亮点,并对 `RPGGameplayAbility` 插件提出全面的重构建议。
### 研究项目
| 项目 | 类型 | 亮点 |
|------|------|------|
| [[LyraStarterGame]] | Epic 官方 UE5 示例 | GameFeature 模块化、GameplayTag 输入路由、装备系统、GamePhase |
| [[GASShooter]] | Epic 官方 UE4 射击示例 | 多 Mesh 蒙太奇、武器能力授予、EffectContainer、可重用 TargetActor |
| [[UE5_GAS_Aura]] | 社区 RPG 教程项目 | 三层属性模型、MMC 派生属性、MVVC WidgetController、DataAsset 驱动 |
### 当前插件现状
`RPGGameplayAbility` 插件基于 GASShooter 框架衍生,已具备:
- ✅ 多 Mesh 蒙太奇复制系统
- ✅ EffectContainer + TargetType 效果容器系统
- ✅ RPC 批处理 (`ShouldDoServerAbilityRPCBatch`)
- ✅ 伤害元属性模式 (DamageExecutionCalc)
- ✅ 可重用 GATA_Trace 瞄准 Actor
- ✅ GameplayMessageSubsystem 基础设施
但存在以下核心架构问题:
- ❌ 硬编码 `EGSAbilityInputID` 枚举输入绑定
- ❌ 单一巨型属性集 (18 个属性)
- ❌ 角色基类手动维护 15+ 个属性 getter 函数
- ❌ 无 AbilitySet DataAsset 模块化能力配置
- ❌ LoadingScreen 模块耦合在 gameplay 插件中
- ❌ 无 GameplayTag 驱动的输入路由
- ❌ 无 MVVM/WidgetController UI 模式
- ❌ 无装备/武器系统与 GAS 集成
- ❌ 无队伍/阵营系统
- ❌ 无 GamePhase 阶段管理
- ❌ 硬编码骨骼名称 (`"b_head"`)
---
## 核心重构优先级
### 优先级 1GameplayTag 输入路由替换硬编码枚举
> [!important] 最高优先级
> 这是影响最大的单一改动Lyra 和 Aura 都采用此模式。
**当前实现(差):**
```cpp
// RPGAbilityTypes.h
UENUM(BlueprintType)
enum class EGSAbilityInputID : uint8 {
None = 0, Confirm = 1, Cancel = 2,
Sprint = 3, Jump = 4, PrimaryFire = 5,
SecondaryFire = 6, AlternateFire = 7,
Reload = 8, NextWeapon = 9, PrevWeapon = 10,
Interact = 11
};
```
**推荐实现Lyra 模式):**
```cpp
// RPGInputConfig.h - DataAsset 驱动
USTRUCT(BlueprintType)
struct FRPGInputAction {
UPROPERTY(EditDefaultsOnly)
TObjectPtr<const UInputAction> InputAction;
UPROPERTY(EditDefaultsOnly)
FGameplayTag InputTag;
};
UCLASS(BlueprintType)
class URPGInputConfig : public UDataAsset {
UPROPERTY(EditDefaultsOnly)
TArray<FRPGInputAction> AbilityInputActions;
UPROPERTY(EditDefaultsOnly)
TArray<FRPGInputAction> NativeInputActions;
};
// RPGInputComponent.h - 模板绑定
class URPGInputComponent : public UEnhancedInputComponent {
template<class UserClass, typename PressedFuncType,
typename ReleasedFuncType, typename HeldFuncType>
void BindAbilityActions(const URPGInputConfig* InputConfig,
UserClass* Object, PressedFuncType PressedFunc,
ReleasedFuncType ReleasedFunc, HeldFuncType HeldFunc);
};
// RpgAbilitySystemComponent.h - ASC 输入处理
void URPGAbilitySystemComponent::AbilityInputTagPressed(FGameplayTag InputTag) {
for (FGameplayAbilitySpec& Spec : ActivatableAbilities.Items) {
if (Spec.GetDynamicSpecSourceTags().HasTagExact(InputTag)) {
Spec.InputPressed = true;
if (Spec.IsActive()) {
AbilitySpecInputPressed(Spec);
} else {
TryActivateAbility(Spec.Handle);
}
}
}
}
```
**优势:**
- 新增能力无需重新编译枚举
- 输入可通过 DataAsset 按角色重新绑定
- GameFeature 插件可在不接触核心代码的情况下添加新输入标签
- 支持 Pressed/Held/Released 三种策略(类似 Aura 的 `AbilityInputTagHeld`/`Released`
---
### 优先级 2拆分巨型属性集
> [!important] 核心架构改动
> Aura 的三层属性模型是 RPG 游戏的标准做法。
**当前问题:** `RPGAttributeSetBase` 包含 18 个属性,混在一起不可拆分。
**推荐结构:**
```cpp
// 第一层:主要属性(可投入加点的属性)
UCLASS()
class URPGVitalAttributeSet : public UAttributeSet {
// Health, MaxHealth, HealthRegenRate
// Mana, MaxMana, ManaRegenRate
// Stamina, MaxStamina, StaminaRegenRate
// Shield, MaxShield, ShieldRegenRate
};
// 第二层:次要属性(通过 MMC 派生的战斗属性)
UCLASS()
class URPGCombatAttributeSet : public UAttributeSet {
// Armor, ArmorPenetration
// CritChance, CritDamage, CritResistance
// BlockChance
// MoveSpeed
};
// 第三层:主要属性(核心加点属性)
UCLASS()
class URPGPrimaryAttributeSet : public UAttributeSet {
// Strength, Intelligence, Agility, Vitality
};
// Meta 属性(临时、非复制、仅服务器)
UCLASS()
class URPGMetaAttributeSet : public UAttributeSet {
// Damage (meta, 仅服务器)
// Healing (meta, 仅服务器)
};
// 进度属性
UCLASS()
class URPGProgressionAttributeSet : public UAttributeSet {
// CharacterLevel, XP, Gold
};
```
**MMC 派生属性计算Aura 模式):**
```cpp
// MMC_MaxHealth.cpp
float UMMC_MaxHealth::CalculateBaseMagnitude_Implementation(
const FGameplayEffectSpec& Spec) const {
float Vitality = 0.f;
GetCapturedAttributeMagnitude(
VitalityDef, Spec, FAggregatorEvaluateParameters(), Vitality);
int32 Level = 1;
if (Spec.GetContext().GetSourceObject()) {
// 通过 ICombatInterface 获取等级
}
return 80.f + 2.5f * Vitality + 10.f * Level;
}
```
---
### 优先级 3引入 AbilitySet DataAsset
> [!important] 模块化配置
> 替换硬编码的 `CharacterAbilities` 数组。
```cpp
USTRUCT(BlueprintType)
struct FRPGGameplayAbilitySet_GameplayAbility {
UPROPERTY(EditDefaultsOnly)
TSubclassOf<URPGGameplayAbility> Ability;
UPROPERTY(EditDefaultsOnly)
int32 AbilityLevel = 1;
UPROPERTY(EditDefaultsOnly)
FGameplayTag InputTag;
UPROPERTY(EditDefaultsOnly)
ERPGAbilityActivationPolicy ActivationPolicy;
};
USTRUCT(BlueprintType)
struct FRPGGameplayAbilitySet_GameplayEffect {
UPROPERTY(EditDefaultsOnly)
TSubclassOf<UGameplayEffect> GameplayEffect;
UPROPERTY(EditDefaultsOnly)
float EffectLevel = 1.f;
};
USTRUCT(BlueprintType)
struct FRPGGameplayAbilitySet_AttributeSet {
UPROPERTY(EditDefaultsOnly)
TSubclassOf<UAttributeSet> AttributeSet;
};
UCLASS(BlueprintType)
class URPGGameplayAbilitySet : public UPrimaryDataAsset {
GENERATED_BODY()
public:
UPROPERTY(EditDefaultsOnly)
TArray<FRPGGameplayAbilitySet_GameplayAbility> GrantedAbilities;
UPROPERTY(EditDefaultsOnly)
TArray<FRPGGameplayAbilitySet_GameplayEffect> GrantedEffects;
UPROPERTY(EditDefaultsOnly)
TArray<FRPGGameplayAbilitySet_AttributeSet> GrantedAttributes;
void GiveToAbilitySystem(
URPGAbilitySystemComponent* ASC,
FRPGGameplayAbilitySet_GrantedHandles& OutHandles,
UObject* SourceObject = nullptr) const;
void TakeFromAbilitySystem(
FRPGGameplayAbilitySet_GrantedHandles& Handles) const;
};
```
**使用场景:**
- 角色职业定义:`DA_FighterAbilitySet``DA_MageAbilitySet`
- 武器/装备授予:装备授予 `DA_SwordAbilitySet`
- 被动技能树:技能树节点授予特定的 AbilitySet
- Buff/Debuff临时添加/移除 AbilitySet
---
### 优先级 4MVVM WidgetController UI 模式
> [!important] UI 解耦
> 当前插件直接在角色代码中 push UI 数据,耦合度高。
**Aura 的 WidgetController 架构:**
```
┌─────────────────────────────────────────────────┐
│ FWidgetControllerParams模型数据
│ - PlayerController │
│ - PlayerState │
│ - AbilitySystemComponent │
│ - AttributeSet │
└──────────────┬──────────────────────────────────┘
┌──────────────▼──────────────────────────────────┐
│ URPGWidgetControllerViewModel 基类) │
│ - BroadcastInitialValues() │
│ - BindCallbacksToDependencies() │
│ - 所有权PlayerController │
└──────────────┬──────────────────────────────────┘
┌──────────┴──────────┐
│ │
┌───▼──────────┐ ┌──────▼──────────┐
│ OverlayWidget │ │ AttributeMenu │
│ Controller │ │ WidgetController│
│ - Health/Mana │ │ - 动态属性菜单 │
│ - Messages │ │ - TagsToAttrs │
└───┬───────────┘ └──────┬──────────┘
│ │
┌───▼─────────────────────▼──────────────────────┐
│ URPGUserWidgetView - UMG Blueprint
│ - SetWidgetController() 事件 │
│ - 绑定 BlueprintAssignable 委托 │
└─────────────────────────────────────────────────┘
```
**HUD 工厂模式:**
```cpp
UCLASS()
class ARPGHUD : public AHUD {
// 懒加载单例工厂
UOverlayWidgetController* GetOverlayWidgetController(
const FRPGWidgetControllerParams& Params);
UAttributeMenuWidgetController* GetAttributeMenuWidgetController(
const FRPGWidgetControllerParams& Params);
};
```
---
### 优先级 5插件模块拆分
**当前问题:** 5 个模块RPGGameplayAbility、CommonLoadingScreen、CommonStartupLoadingScreen、GameplayMessageRuntime、GameplayMessageNodes全部在一个插件中。
**推荐结构:**
```
Plugins/
├── RPGGameplayAbility/ # 核心 GAS 扩展
│ ├── Source/
│ │ └── RPGGameplayAbility/ # 唯一模块
│ └── RPGGameplayAbility.uplugin
├── CommonLoadingScreen/ # 独立加载画面插件
│ └── CommonLoadingScreen.uplugin
├── CommonStartupLoadingScreen/ # 独立启动加载画面插件
│ └── CommonStartupLoadingScreen.uplugin
└── GameplayMessageRouter/ # 消息路由器(保持独立)
├── GameplayMessageRuntime/
└── GameplayMessageNodes/
```
---
## 各系统详细重构建议
### 1. ASC 扩展 (URPGAbilitySystemComponent)
**保留:**
- 多 Mesh 蒙太奇复制系统(格斗游戏需要 1P/3P 双骨骼)
- RPC 批处理 (`ShouldDoServerAbilityRPCBatch`)
- Blueprint 标签操作辅助函数
- 本地 GameplayCue 执行
**新增(来自 Lyra**
| 功能 | 说明 |
|------|------|
| `AbilityInputTagPressed/Released/Held` | GameplayTag 驱动的输入处理 |
| `ProcessAbilityInput(DeltaTime)` | 每帧统一的输入分发 |
| 激活组系统 | Independent / Exclusive_Replaceable / Exclusive_Blocking |
| 动态 Tag GE 应用 | 运行时 Tag 管理 |
| TagRelationshipMapping 支持 | 跨能力阻塞/取消关系 |
**新增(来自 Aura**
| 功能 | 说明 |
|------|------|
| `ClientEffectApplied` RPC | GE 应用时客户端通知 UI |
| `m_EffectAssetTag` 多播委托 | Widget 创建触发 |
**激活组系统(格斗游戏关键):**
```cpp
UENUM(BlueprintType)
enum class ERPGAbilityActivationGroup : uint8 {
Independent, // 不阻塞任何能力,不被任何能力阻塞
Exclusive_Replaceable, // 可被其他 Exclusive 能力取消
Exclusive_Blocking, // 阻塞其他 Exclusive 能力,自身不可被取消
};
// 使用场景:
// - 普通攻击Independent可叠加
// - 必杀技Exclusive_Replaceable会被新必杀技取消
// - 超必杀技Exclusive_Blocking不可取消阻塞其他技能
// - 防御/受击Exclusive_Blocking不可取消
```
---
### 2. GameplayAbility 基类 (URPGGameplayAbility)
**保留:**
- EffectContainer 系统Tag → TargetType + GEs
- 自定义 Cost 检查RPGCheckCost/RPGApplyCost BlueprintNativeEvent
- 多 Mesh 动画辅助函数
**新增(来自 Lyra**
```cpp
UENUM(BlueprintType)
enum class ERPGAbilityActivationPolicy : uint8 {
OnInputTriggered, // 按键按下触发
WhileInputActive, // 按键持续期间激活
OnSpawn, // 授予时立即激活(被动能力)
OnRhythmBeat, // 节奏节拍触发MusicFighter 特有)
};
// 组合式 Cost 系统
UCLASS(Abstract, EditInlineNew, DefaultToInstanced)
class URPGAbilityCost : public UObject {
virtual bool CheckCost(const URPGGameplayAbility* Ability,
const FGameplayAbilitySpecHandle Handle,
const FGameplayAbilityActorInfo* ActorInfo,
FGameplayTagContainer* OptionalRelevantTags) const;
virtual void ApplyCost(const URPGGameplayAbility* Ability,
const FGameplayAbilitySpecHandle Handle,
const FGameplayAbilityActorInfo* ActorInfo,
const FGameplayAbilityActivationInfo ActivationInfo);
};
// 子类:
// - URPGAbilityCost_GameplayEffectGE 消耗)
// - URPGAbilityCost_ItemTagStack物品标记栈消耗如弹药
// - URPGAbilityCost_Attribute直接属性消耗如怒气值
```
**删除/替换:**
- `EGSAbilityInputID AbilityInputID``FGameplayTag StartupInputTag`
- `bActivateOnInput``ERPGAbilityActivationPolicy ActivationPolicy`
- `bSourceObjectMustEqualCurrentWeaponToActivate` → 泛化为 Tag 需求检查
---
### 3. 属性系统 - 完整重构
```
Primary Attributes主要/可投资属性)
├── Strength → 影响 PhysicalAttack, MaxHealth
├── Intelligence → 影响 MagicAttack, MaxMana
├── Agility → 影响 CritChance, MoveSpeed, DodgeChance
└── Vitality → 影响 MaxHealth, MaxStamina, HealthRegenRate
Secondary Attributes派生/战斗属性 - 通过 MMC 计算)
├── MaxHealth = f(Vitality, Level)
├── MaxMana = f(Intelligence, Level)
├── MaxStamina = f(Vitality, Level)
├── PhysicalAttack = f(Strength, Level)
├── MagicAttack = f(Intelligence, Level)
├── Armor = f(Agility, Vitality, Level)
├── ArmorPenetration = f(Strength, Level)
├── CritChance = f(Agility, Level)
├── CritDamage = 1.5x (基础) + 装备加成
├── CritResistance = f(Vitality, Level)
├── BlockChance = f(Strength, Level)
├── DodgeChance = f(Agility, Level)
└── MoveSpeed = Base(400) + f(Agility, Level)
Vital Attributes运行时资源
├── Health → [0, MaxHealth]
├── Mana → [0, MaxMana]
└── Stamina → [0, MaxStamina]
Meta Attributes临时服务器专用
├── Damage → ExecutionCalc 写入 → PostGameplayEffectExecute 处理后归零
└── Healing → HealingExecutionCalc 写入 → 处理后归零
Progression进度
├── CharacterLevel → 影响所有 MMC 计算
├── XP → 经验值
└── Gold → 货币
```
**伤害计算管道:**
```
1. 技能设置 SetByCaller Magnitude (Tag: "Data.Damage")
2. URPGDamageExecutionCalc 捕获:
- Source: PhysicalAttack/MagicAttack
- Target: Armor, ArmorPenetration, CritResistance, BlockChance, DodgeChance
3. 计算流程:
a. 命中判定 (DodgeChance)
b. 暴击判定 (CritChance vs CritResistance)
c. 格挡判定 (BlockChance)
d. 护甲减免 (Armor vs ArmorPenetration)
e. 属性克制修正(元素标签)
f. 最终伤害写入 Target.Damage
4. PostGameplayEffectExecute:
a. Shield 吸收
b. Health 扣减 → Clamp
c. 存活/死亡判定 → 广播 (GameplayMessageSubsystem)
```
---
### 4. 瞄准系统
**保留:**
- `URPGTargetType` 蓝图化瞄准逻辑
- `RPGATA_Trace` / `RPGATA_LineTrace` / `RPGATA_SphereTrace`
**新增(格斗游戏专用):**
```cpp
// 近战弧形瞄准
UCLASS(Blueprintable)
class URPGTargetType_MeleeArc : public URPGTargetType {
UPROPERTY(EditDefaultsOnly)
float ArcAngle = 90.f; // 弧形角度
UPROPERTY(EditDefaultsOnly)
float ArcRadius = 200.f; // 弧形半径
};
// AOE 圆形瞄准
UCLASS(Blueprintable)
class URPGTargetType_CircleAOE : public URPGTargetType {
UPROPERTY(EditDefaultsOnly)
float Radius = 300.f;
};
// 组合状态过滤
// "已在此连招中被击中过的目标不重复选取"
void GetTargets_Implementation(...) {
// 检查 Combat.AlreadyHit 标签
for (AActor* Target : Candidates) {
if (!Target->HasMatchingGameplayTag(Combat_AlreadyHit)) {
OutActors.Add(Target);
}
}
}
```
---
### 5. 输入系统
**替换整个 `EGSAbilityInputID` 枚举为以下架构:**
```
┌─────────────────────────┐
│ URPGInputConfig │ DataAsset
│ - AbilityInputActions │ 映射 InputAction → GameplayTag
│ - NativeInputActions │
└───────────┬─────────────┘
┌───────────▼─────────────┐
│ URPGInputComponent │ extends UEnhancedInputComponent
│ - BindAbilityActions() │ 模板函数,自动绑定
└───────────┬─────────────┘
┌───────────▼─────────────┐
│ ULyraHeroComponent │ (或 RPGHeroComponent)
│ - InitializePlayerInput│
└───────────┬─────────────┘
┌───────────▼─────────────┐
│ URPGAbilitySystemComp │
│ - AbilityInputTagPressed│ 匹配 DynamicSpecSourceTags
│ - AbilityInputTagReleased│
│ - AbilityInputTagHeld │
│ - ProcessAbilityInput │ 每帧统一处理
└─────────────────────────┘
```
**MusicFighter 特有:节奏输入缓冲**
```cpp
// 在 ProcessAbilityInput 中
void URPGAbilitySystemComponent::ProcessAbilityInput(float DeltaTime, bool bGamePaused) {
// ... 标准处理 ...
// 节奏检测
if (bIsOnBeat) {
for (FGameplayAbilitySpec& Spec : ActivatableAbilities.Items) {
if (Spec.Ability->GetActivationPolicy() == OnRhythmBeat) {
// 应用节奏加成标签
Spec.DynamicSpecSourceTags.AddTag(RhythmBonusTag);
}
}
}
// 输入缓冲(格斗游戏标准做法)
FlushInputBuffer(DeltaTime);
}
```
---
### 6. UI 系统
**当前问题:** 直接在 Character/PlayerState/PlayerController 中 push UI 数据。
**使用 Aura 的 MVVC 模式替换:**
```cpp
// WidgetController 管理 ASC 委托绑定
// Widget (UMG) 仅负责显示
// 中间通过 BlueprintAssignable 委托通信
// 消息 Widget 通过 DataTable 驱动:
USTRUCT(BlueprintType)
struct FRPGMessageWidgetRow : public FTableRowBase {
UPROPERTY(EditAnywhere)
FGameplayTag MessageTag;
UPROPERTY(EditAnywhere)
TSubclassOf<URPGUserWidget> MessageWidgetClass;
UPROPERTY(EditAnywhere)
UTexture2D* MessageImage;
UPROPERTY(EditAnywhere)
FText MessageText;
};
```
**GameplayMessageSubsystem 集成:**
```cpp
// 替换直接调用 PC->ShowDamageNumber(...)
// 使用消息通道广播:
UGameplayMessageSubsystem::Get(this).BroadcastMessage(
RPGGameplayTags::Get().DamageDealt,
FRPGDamageMessage{
Instigator, Target, Damage, DamageTags
}
);
// UI Widget 订阅:
UGameplayMessageSubsystem::Get(this).RegisterListener<FRPGDamageMessage>(
RPGGameplayTags::Get().DamageDealt,
this, &URPGDamageWidget::OnDamageMessage
);
```
---
### 7. 装备系统
> [!note] 新增功能
> 当前插件无装备系统,使用 Lyra 模式新增。
```cpp
// 装备定义DataAsset
UCLASS(BlueprintType)
class URPGEquipmentDefinition : public UObject {
UPROPERTY(EditDefaultsOnly)
TSubclassOf<URPGEquipmentInstance> InstanceType;
UPROPERTY(EditDefaultsOnly)
TArray<URPGGameplayAbilitySet*> AbilitySetsToGrant;
UPROPERTY(EditDefaultsOnly)
TArray<FRPGEquipmentActorToSpawn> ActorsToSpawn;
};
// 装备实例(运行时)
UCLASS(BlueprintType)
class URPGEquipmentInstance : public UObject {
// 授予的能力句柄
FRPGGameplayAbilitySet_GrantedHandles GrantedHandles;
// 关联的源对象(武器/乐器/道具)
UObject* GetInstigator() const;
};
// 装备管理器组件(挂在 Pawn 上)
UCLASS()
class URPGEquipmentManagerComponent : public UPawnComponent {
UFUNCTION(BlueprintCallable)
void EquipItem(TSubclassOf<URPGEquipmentDefinition> EquipmentDef);
UFUNCTION(BlueprintCallable)
void UnequipItem(URPGEquipmentInstance* EquipmentInstance);
};
// 装备能力基类
UCLASS()
class URPGGameplayAbility_FromEquipment : public URPGGameplayAbility {
// 可反查装备实例获取属性/状态
URPGEquipmentInstance* GetAssociatedEquipment() const;
};
```
---
### 8. GamePhase 阶段系统
> [!note] 新增功能
> 音乐格斗游戏需要回合管理。
```cpp
UCLASS()
class URPGamePhaseSubsystem : public UWorldSubsystem {
// 使用层级 GameplayTag 管理阶段
// Game.WaitingForPlayers
// Game.Countdown
// Game.Playing.Round1
// Game.Playing.Round1.Break
// Game.Playing.Round2
// Game.ShowingResult
void StartPhase(TSubclassOf<URPGamePhaseAbility> PhaseAbility,
FRPGamePhaseDelegate PhaseEndedCallback);
void WhenPhaseStartsOrIsActive(FGameplayTag PhaseTag,
EPhaseTagMatchType MatchType,
const FRPGamePhaseTagDelegate& WhenActive);
void WhenPhaseEnds(FGameplayTag PhaseTag,
EPhaseTagMatchType MatchType,
const FRPGamePhaseTagDelegate& WhenEnd);
};
// 阶段能力
UCLASS()
class URPGamePhaseAbility : public URPGGameplayAbility {
// ReplicationPolicy = ReplicateNo
// NetExecutionPolicy = ServerInitiated
// NetSecurityPolicy = ServerOnly
UPROPERTY(EditDefaultsOnly)
FGameplayTag GamePhaseTag;
};
```
**能力阶段门控:**
- `ActivationRequiredTags` 添加 `Game.Playing` → 非 Playing 阶段无法使用能力
- `ActivationBlockedTags` 添加 `Game.ShowingResult` → 结果显示时禁用能力
- 阶段观察者音乐播放、UI 切换、生成逻辑
---
### 9. 队伍系统
> [!note] 新增功能
> 格斗游戏需要队伍/阵营支持。
```cpp
UCLASS()
class URPGTeamSubsystem : public UWorldSubsystem {
void ChangeTeamForActor(AActor* Actor, int32 NewTeamId);
int32 FindTeamFromObject(UObject* Obj) const;
bool CanCauseDamage(AActor* Instigator, AActor* Target) const;
// 队伍标记栈(跟踪队伍得分等)
void AddTeamTagStack(int32 TeamId, FGameplayTag Tag, int32 Count);
void RemoveTeamTagStack(int32 TeamId, FGameplayTag Tag, int32 Count);
int32 GetTeamTagStackCount(int32 TeamId, FGameplayTag Tag) const;
};
// ILyraTeamAgentInterface 实现
class ILyraTeamAgentInterface : public IGenericTeamAgentInterface {
FOnLyraTeamIndexChangedDelegate OnTeamChanged;
};
```
---
## 实施路线图
### 阶段 1基础改造低风险、高回报
| # | 改动 | 来<><E69DA5><EFBFBD> | 影响范围 |
|---|------|------|----------|
| 1 | 拆分属性集为 Primary/Combat/Vital/Meta/Progression | Aura | 属性系统 |
| 2 | GameplayTag 输入路由替换 EGSAbilityInputID 枚举 | Lyra | 输入/ASC |
| 3 | 创建 RPGInputConfig DataAsset + RPGInputComponent | Lyra+Aura | 输入 |
| 4 | 实现 AbilitySet DataAsset 模块化能力授予 | Lyra | 能力授予 |
### 阶段 2核心改进
| # | 改动 | 来源 | 影响范围 |
|---|------|------|----------|
| 5 | 能力激活策略 (OnInputTriggered/WhileInputActive/OnSpawn/OnRhythmBeat) | Lyra | 能力基类 |
| 6 | MMC 派生属性计算(含等级缩放) | Aura | 属性系统 |
| 7 | 激活组系统(格斗游戏攻击取消) | Lyra | ASC |
| 8 | 重构伤害管道Meta属性 + ExecutionCalc | Lyra+GASShooter | 伤害 |
| 9 | ClientEffectApplied RPC UI 通知 | Aura | ASC/UI |
### 阶段 3架构升级
| # | 改动 | 来源 | 影响范围 |
|---|------|------|----------|
| 10 | MVVM WidgetController UI 模式 | Aura | UI |
| 11 | 拆分 LoadingScreen 为独立插件 | 最佳实践 | 插件结构 |
| 12 | GameplayMessageSubsystem 集成(解耦事件) | Lyra | 全局通信 |
| 13 | 装备系统(装备 → AbilitySet → ASC | Lyra | 装备/物品 |
| 14 | GamePhase 阶段系统(回合管理) | Lyra | 游戏流程 |
### 阶段 4高级特性
| # | 改动 | 来源 | 影响范围 |
|---|------|------|----------|
| 15 | TagRelationshipMapping 跨能力阻塞/取消 | Lyra | 能力管理 |
| 16 | 组合式能力 Cost 系统 | Lyra | 能力消耗 |
| 17 | 队伍子系统 | Lyra | 队伍/阵营 |
| 18 | GameFeature 模块化扩展 | Lyra | 插件架构 |
| 19 | Save/Load GAS 状态序列化 | 自定义 | 存档 |
---
## MusicFighterGame 特有建议
### 节奏输入系统
```cpp
// 在 ASC 中添加
void URPGAbilitySystemComponent::SetCurrentBeatFraction(float BeatFraction) {
// 从 FMOD/AudioAnalysis 获取节拍数据
CurrentBeatPrecision = CalculateBeatPrecision(BeatFraction);
if (CurrentBeatPrecision < PerfectThreshold) {
// Perfect 判定
AddDynamicTagToAllAbilities(RhythmPerfectTag);
} else if (CurrentBeatPrecision < GoodThreshold) {
// Good 判定
AddDynamicTagToAllAbilities(RhythmGoodTag);
}
}
```
### 连招系统建议
```
利用 GameplayTag 层级管理连招状态:
- Combat.Combo.Hit1 → Combat.Combo.Hit2 → Combat.Combo.Hit3
- 每个连招段使用 EffectContainer Map 的不同 Tag
- 下一段能力需要上一段的 Tag 作为 ActivationRequiredTag
- 节奏加成通过 SetByCaller 修改伤害系数
```
### 乐器/武器即 AbilitySource
```
游戏中的乐器(吉他、贝斯、鼓、键盘)作为 Equipment
- 每个乐器有独立的 AbilitySet
- 不同乐器授予不同的攻击模式和效果
- 节奏精准度影响伤害倍率
- 装备管理器处理乐器切换
```
---
## 对比总结
| 系统 | 当前状态 | 目标状态 | 参考来源 |
|------|----------|----------|----------|
| 输入路由 | 硬编码枚举 | GameplayTag 驱动 | Lyra |
| 属性系统 | 单一 18 属性集 | 5 个分层属性集 + MMC | Aura |
| 能力配置 | CharacterAbilities 数组 | AbilitySet DataAsset | Lyra |
| UI 模式 | 直接 Push | MVVM WidgetController | Aura |
| 伤害计算 | ExecutionCalc + AttributeSet 混用 | 完整 Meta 属性管道 | Lyra+GASShooter |
| 插件模块 | 5 模块混装 | 核心 + 独立 LoadingScreen | 最佳实践 |
| 装备系统 | 无 | 装备 → AbilitySet → ASC | Lyra |
| 阶段管理 | 无 | 层级 Tag GamePhase 子系统 | Lyra |
| 队伍系统 | 无 | TeamSubsystem + TeamAgent | Lyra |
| 消息通信 | 已引入未使用 | GameplayMessageSubsystem 全系统集成 | Lyra |
| 多 Mesh 蒙太奇 | ✅ 已实现 | 保留并优化 | GASShooter |
| EffectContainer | ✅ 已实现 | 保留并扩展类型 | GASShooter |
| RPC 批处理 | ✅ 已实现 | 保留 | GASShooter |
---
## 附录
### 参考项目文件索引
**LyraStarterGame:**
- `Source/LyraGame/AbilitySystem/LyraAbilitySystemComponent.h` - ASC 标签输入 + 激活组
- `Source/LyraGame/AbilitySystem/Abilities/LyraGameplayAbility.h` - 能力基类 + 策略
- `Source/LyraGame/AbilitySystem/LyraAbilitySet.h` - AbilitySet DataAsset
- `Source/LyraGame/AbilitySystem/Phases/LyraGamePhaseSubsystem.h` - 阶段子系统
- `Source/LyraGame/AbilitySystem/Attributes/LyraHealthSet.h` - 元属性模式
- `Source/LyraGame/Equipment/LyraEquipmentDefinition.h` - 装备定义
- `Source/LyraGame/Input/LyraInputConfig.h` - 输入 DataAsset
- `Source/LyraGame/GameFeatures/GameFeatureAction_AddAbilities.h` - 模块化能力授予
- `Plugins/GameplayMessageRouter/Source/.../GameplayMessageSubsystem.h` - 消息系统
**GASShooter:**
- `Source/GASShooter/Characters/Abilities/GSAbilitySystemComponent.h` - 多 Mesh ASC
- `Source/GASShooter/Characters/Abilities/GSGameplayAbility.h` - 能力基类
- `Source/GASShooter/Characters/Abilities/AttributeSets/GSAttributeSetBase.h` - 属性集
- `Source/GASShooter/Characters/Abilities/GSDamageExecutionCalc.cpp` - 伤害计算
- `Source/GASShooter/Characters/Abilities/GSAbilityTypes.h` - EffectContainer
- `Source/GASShooter/Weapons/GSWeapon.h` - 武器系统
- `Source/GASShooter/Characters/Abilities/GSGATA_Trace.h` - 瞄准系统
**UE5_GAS_Aura:**
- `Source/Aura/Public/AbilitySystem/AuraAbilitySystemComponent.h` - Tag 输入 ASC
- `Source/Aura/Public/AbilitySystem/AuraAttributeSet.h` - 三层属性集 + TagsToAttributes
- `Source/Aura/Public/AbilitySystem/Abilities/AuraGameplayAbility.h` - 能力基类
- `Source/Aura/Public/AbilitySystem/ModMagCalc/MMC_MaxHealth.cpp` - MMC 示例
- `Source/Aura/Public/Input/AuraInputConfig.h` - 输入 DataAsset
- `Source/Aura/Public/Input/AuraInputComponent.h` - 输入组件模板
- `Source/Aura/Public/UI/WidgetController/AuraWidgetController.h` - WidgetController 基类
- `Source/Aura/Public/UI/WidgetController/OverlayWidgetController.cpp` - UI 绑定示例
- `Source/Aura/Public/UI/WidgetController/AttributeMenuWidgetController.cpp` - 动态属性菜单
- `Source/Aura/Public/UI/HUD/AuraHUD.h` - HUD 工厂
---
> 本文档基于 2024-05-30 对三个参考项目的深度代码分析编写。
> 所有推荐模式均已在对应项目中验证可行。