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

文章目录


前言

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

  1. AttributeSet 的作用和结构

  2. FGameplayAttribute 的底层机制

  3. 属性是如何被修改的

  4. 多人同步的技术原理

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

一、Attribute System 架构概览

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

核心类关系:

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

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

二、UAttributeSet:属性类本体

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

cpp 复制代码
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 中实际存储属性值的类型:

cpp 复制代码
struct FGameplayAttributeData
{
    float BaseValue;
    float CurrentValue;
};

:
BaseValue:基础值,不随 BUFF 等效果改变

复制代码
CurrentValue:实际数值,会受 GE 动态影响   

内建了属性变更检测与 NetDeltaSerialize 支持

🧬 四、FGameplayAttribute:属性引用包装器

为了让 GE、GA 以"泛型方式"修改属性(而不是硬编码字段名),GAS 提供了 FGameplayAttribute:

cpp 复制代码
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() 同步客户端

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

六、属性计算流程

GAS 支持多个层级的属性修改:

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

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

cpp 复制代码
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 修改)

:
不要在游戏逻辑中直接 Health = xxx

复制代码
必须通过 ASC 和 GE 修改属性!

:
不会触发 OnRep

复制代码
不会触发 PostGameplayEffectExecute   

不参与网络同步

推荐方法:

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

九、案例:实现护甲减伤

  1. 定义两个属性:Health, Armor
  2. 创建一个 Execution Calculation 类,逻辑如下:
cpp 复制代码
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
相关推荐
RuoyiOffice6 分钟前
企业请假销假系统设计实战:一张表、一套流程、两段生命周期——BPM节点驱动的表单变形术
java·spring·uni-app·vue·产品运营·ruoyi·anti-design-vue
鹤旗7 分钟前
While语句,do-while语句,for语句
java·jvm·算法
WarrenMondeville8 分钟前
2.Unity面向对象- 开闭原则
unity·游戏引擎·开闭原则
小碗羊肉17 分钟前
【从零开始学Java | 第十八篇】BigInteger
java·开发语言·新手入门
sky wide27 分钟前
[特殊字符] Docker Swarm 集群搭建指南
java·docker·容器
wuqingshun31415932 分钟前
谈谈你对springAop动态代理的理解?
java·jvm
执笔画流年呀34 分钟前
PriorityQueue(堆)续集
java·开发语言
武超杰43 分钟前
Spring Boot入门教程
java·spring boot·后端
左左右右左右摇晃43 分钟前
JDK 1.7 ConcurrentHashMap——分段锁
java·开发语言·笔记
呆呆敲代码的小Y1 小时前
UnityMCP+Claude+VSCode,构建最强AI游戏开发环境
人工智能·vscode·游戏·unity·游戏引擎·u3d·mcp