AttributeSet:属性的栖息地

结构

属性不是散落在各处的变量,全部放在一个 UAttributeSet 子类里:

UCLASS()
class UMyAttributeSet : public UAttributeSet
{
    GENERATED_BODY()
public:
    // 生命
    UPROPERTY(BlueprintReadOnly, Category="Health")
    FGameplayAttributeData Health;
    UPROPERTY(BlueprintReadOnly, Category="Health")
    FGameplayAttributeData MaxHealth;

    // 法力
    UPROPERTY(BlueprintReadOnly, Category="Mana")
    FGameplayAttributeData Mana;
    UPROPERTY(BlueprintReadOnly, Category="Mana")
    FGameplayAttributeData MaxMana;
};

每个 FGameplayAttributeData 内部有 BaseValue(基础值,决定"上限一类")与 CurrentValue(当前值,决定"此刻多少")。

初始化:三种做法

做法 适合 说明
构造函数直接 SetBaseValue 固定初始属性 简单,部分场景不权威
效果初始化(用一个"初始化 GE") 推荐,数值可配 配一个 Instant GE 设基础值
数据表(DataTable)驱动 属性随等级/职业变化 GE 从表格读值

推荐做法:配一个 GE_InitStats(Instant GE),Modifiers 里把 MaxHealth 等设为需要的基础值,角色 BeginPlay 时应用一次。

为什么这样比构造函数直接写好?——因为"100 级时 MaxHealth 多少"这类数值应当走配置资产,而不是硬编码在 C++ 里(第 1 本提到的"数据配置化"原则在 GAS 里的体现)。

在 C++ 里取属性

const UMyAttributeSet* Set = ASC->GetSet<UMyAttributeSet>();
float Cur = Set->GetHealth();
float Max = Set->GetMaxHealth();

蓝图里可直接 Get Health / Get MaxHealth(AttributeSet 的变量默认 BlueprintReadOnly——建议只读,写只走 GE)。

属性变化通知(UI 绑定的基础)

AttributeSet 有 PreAttributeChange / PostGameplayEffectExecute 两个回调:

void UMyAttributeSet::PostGameplayEffectExecute(const FGameplayEffectModCallbackData& Data)
{
    Super::PostGameplayEffectExecute(Data);
    if (Data.EvaluatedData.Attribute == GetHealthAttribute())
    {
        // 通知 UI、拼受击飘字
        OnHealthChanged.Broadcast(GetHealth());
    }
}

GAS 官方推荐把 UI 通知放在 AttributeSet 里——它是所有 GE 的公共下游。

本章小结

  • 属性集中放 AttributeSet,每个属性 = BaseValue(基础)+ CurrentValue(当前)。
  • 初始化推荐"初始化 GE",数值走配置资产。
  • UI 监听走 AttributeSet 的 PostGameplayEffectExecute 回调。