虚幻GAS底层原理解剖三 (GA)


前言

现在深入分析 GAS 中 Attribute System 的底层实现原理,包括:

  1. AttributeSet 的作用和结构

  2. FGameplayAttribute 的底层机制

  3. 属性是如何被修改的

  4. 多人同步的技术原理

  5. GAS 如何保证属性安全性、灵活性与效率

一、Attribute System 架构概览

Attribute System 是 GAS 的核心基础,用于统一管理角色的数值属性(如血量、攻击力、护甲、速度等)。

核心类关系:

UAttributeSet           // 属性集合类,定义具体属性
    ↑
FGameplayAttribute      // 属性引用结构,用于泛型操作
    ↑
UAbilitySystemComponent // 管理所有 AttributeSet + 与 GE 交互

它并不直接处理逻辑,而是 通过 ASC、GE、Tag 等统一修改和同步数值属性。

二、UAttributeSet:属性类本体

UAttributeSet 是一个继承自 UObject 的类,开发者可自定义子类,在其中定义属性字段:

UCLASS()
class UMyAttributeSet : public UAttributeSet
{
    GENERATED_BODY()

public:
    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Health", ReplicatedUsing = OnRep_Health)
    FGameplayAttributeData Health;

    UFUNCTION()
    void OnRep_Health(const FGameplayAttributeData& OldHealth);

    static FGameplayAttribute GetHealthAttribute();
};
说明:
每个属性都是 FGameplayAttributeData 类型
该类型封装了 float 值,支持缓冲、同步、变动检测等
可通过 OnRep_XXX() 实现属性同步的回调

三、FGameplayAttributeData 的作用

它是 GAS 中实际存储属性值的类型:

struct FGameplayAttributeData
{
    float BaseValue;
    float CurrentValue;
};
特性:
BaseValue:基础值,不随 BUFF 等效果改变
CurrentValue:实际数值,会受 GE 动态影响
内建了属性变更检测与 NetDeltaSerialize 支持

🧬 四、FGameplayAttribute:属性引用包装器
为了让 GE、GA 以“泛型方式”修改属性(而不是硬编码字段名),GAS 提供了 FGameplayAttribute:

FGameplayAttribute MyAttribute = UMyAttributeSet::GetHealthAttribute();
ASC->SetNumericAttributeBase(MyAttribute, 100.0f);
其本质是包装了:
所属 UClass*(哪个 AttributeSet)
属性名 FName
C++ 成员指针

并通过反射方式获取对应的 FGameplayAttributeData& 实例。

五、属性变更流程

属性变更路径(以 GE 加血为例):

  1. GE 的 FModifierSpec 指定修改 Health
  2. GE 应用到目标 ASC → 调用 ApplyModToAttribute()
  3. 找到 AttributeSet → 定位到 FGameplayAttributeData
  4. 修改 CurrentValue → 触发 PostGameplayEffectExecute()

若是网络游戏,调用 OnRep_Health() 同步客户端

void UAttributeSet::PostGameplayEffectExecute(const FGameplayEffectModCallbackData& Data)
{
    if (Data.Attribute == GetHealthAttribute()) {
        if (Health.GetCurrentValue() <= 0.f) {
            // 死亡逻辑
        }
    }
}

六、属性计算流程
GAS 支持多个层级的属性修改:

层级修改函数特性
BaseSetBaseAttributeValue基础值
CurrentApplyModToAttribute当前值
额外运算Execution Calculation动态伤害、暴击等

在执行 GE 时,会通过 FAggregator 系统完成对属性的加权合并运算:

float NewValue = BaseValue
               + AdditiveModifiers
               + MultiplicativeModifiers
               + Override (if any);

这些 Modifier 都存储在 ASC 的内部结构 FAggregatorMap 中,并会在任意值变动时自动重新计算属性。
七、属性网络同步原理
GAS 的属性同步机制非常高效:

  1. 使用 NetDeltaSerialize + FGameplayAttributeData
    每个属性结构都注册了 Delta 序列化:

cpp
复制
编辑
void FGameplayAttributeData::NetSerialize(FArchive& Ar, class UPackageMap* Map, bool& bOutSuccess)
只有当属性值变动时,才会序列化发送

自动触发 OnRep_属性名() 回调

  1. GAS 会为所有 AttributeSet 注册为子对象并同步
    在 ASC 初始化时会自动注册属性集合并设置 RepNotify:

cpp
复制
编辑
ASC->AddReplicatedSubObject(AttributeSetInstance);

八、属性保护机制(只通过 GE 修改)

GAS 强烈建议:
不要在游戏逻辑中直接 Health = xxx
必须通过 ASC 和 GE 修改属性!
否则:
不会触发 OnRep
不会触发 PostGameplayEffectExecute
不参与网络同步

推荐方法:

FGameplayEffectSpecHandle Spec = MakeOutgoingSpec(HealthRestoreGE, 1.0f, Context);
ASC->ApplyGameplayEffectSpecToSelf(*Spec.Data.Get());

九、案例:实现护甲减伤

  1. 定义两个属性:Health, Armor
  2. 创建一个 Execution Calculation 类,逻辑如下:
float Damage = InDamage;
float Armor = 0.f;
ExecParams.AttemptCalculateCapturedAttributeMagnitude(ArmorDef, EvalParams, Armor);
Damage *= (1 - Armor * 0.01f);  // 减伤公式
  1. 设置 OutSpec.AddOutputModifier() 作用到 Health 属性上

总结

模块作用说明
UAttributeSet属性定义类包含各个 FGameplayAttributeData
FGameplayAttributeData属性值结构有 Base 和 Current 值,支持序列化
FGameplayAttribute泛型引用器可用于在运行时访问属性
ASC执行属性修改持有属性容器、同步、处理 GE
### 虚幻引擎中的GASGameplay Ability System) #### GAS的核心功能 Gameplay Ability System (GAS)虚幻引擎的一个内置插件,提供了强大的框架来实现角色技能、属性系统以及状态效果等功能。它支持复杂的数值计算、能力消耗与冷却机制,并集成了网络同步和预测功能[^3]。 #### 插件激活 要在项目中使用 GAS,需先在插件管理器中启用该插件。一旦启用,可以通过 `AbilitySystemComponent` 来管理和执行各种能力和属性操作。 #### 主要组成部分 1. **Abilities(能力)** Abilities 定义了游戏中可触发的行为或动作,例如攻击、施法或其他交互行为。它们通常绑定到特定输入事件并具有自己的逻辑脚本。每个 Ability 可以设置资源成本(如生命值或能量)、持续时间及冷却周期。 2. **Attributes(属性)** Attributes 表示实体的基础数据项,比如健康度、耐力或者力量等级等。这些动态变化的数据由 `AttributeSet` 类型定义并通过 `AbilitySystemComponent` 进行更新维护。 3. **Effects(效果)** Effects 用于描述当某个条件满足时所发生的变化,可能涉及修改目标单位的一系列参数或是附加特殊标记(Tag)。常见的例子有伤害加成、减速惩罚等等。 4. **Gameplay Tags 和 Gameplay Events** - **Gameplay Tags**: 提供了一种灵活的方式来分类和检索游戏内的元素。几乎所有的核心结构都支持关联标签以便于查询匹配。 - **Gameplay Events**: 允许广播自定义消息给监听者列表从而驱动复杂互动链路的发生发展过程。 5. **Network Replication & Prediction** 鉴于多人在线环境下的需求考量,GAS 设计之初就充分考虑到了跨客户端间一致性保障的重要性,因此包含了完备可靠的网路传输解决方案. #### 示例代码展示如何创建简单的Skill System基于GAS: ```cpp // MyCharacter.h UCLASS() class MYPROJECT_API AMyCharacter : public ACharacter { GENERATED_BODY() public: UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Components") UAbilitySystemComponent* AbilitySystemComp; protected: virtual void BeginPlay() override; }; // MyCharacter.cpp #include "MyCharacter.h" #include "AbilitySystemBlueprintLibrary.h" AMyCharacter::AMyCharacter(const FObjectInitializer& ObjectInitializer) { AbilitySystemComp = CreateDefaultSubobject<UAbilitySystemComponent>(TEXT("AbilitySystemComp")); } void AMyCharacter::BeginPlay() { Super::BeginPlay(); if(AbilitySystemComp && HasAuthority()) { // Grant abilities on server side only. FGameplayAbilitySpecDef SpecDef; SpecDef.Ability = StaticClass()->FindFunctionByName(FName(TEXT("ExecuteBasicAttack"))); SpecDef.InputID = EInputAction::IA_BasicAttack; // Assuming you have this enum defined elsewhere const TArray<FGameplayEffectContextHandle> ContextHandles; AbilitySystemComp->GiveAbility(SpecDef); // Initialize default attributes here... } } ``` 上述片段展示了怎样在一个继承自ACharacter类的新角色身上添加基本战斗技巧的能力授予方法。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值