AttributeSet 负责定义和持有属性并且管理属性的变化。开发者可以子类化UAttributeSet。在OwnerActor的构造方法中创建的AttributeSet将会自动注册到ASC。这一步必须在C++中完成。
Attributes 是由 FGameplayAttributeData定义的浮点值。 Attributes能够表达从角色的生命值到角色等级到药瓶的价格等任何数值。 如果Actor拥有游戏性相关的数值,那么可以考虑使用Attribute。Attributes 通常只能被GameplayEffects 修改,因此ASC可以 预测 这个修改。
一个Attribute 由两个值构成 - 一个基值 BaseValue 和一个当前值CurrentValue. 基值BaseValue是属性 Attribute的一个恒值, 而当前值 CurrentValue 是 BaseValue 加上GameplayEffects的临时修改值。
立即(Instant) GameplayEffects将永久改变BaseValue,而持续(Duration) 和永恒(Infinite) GameplayEffects 将改变CurrentValue。周期性(Periodic )GameplayEffects像立即(Instant) GameplayEffects一样将改变BaseValue。
这里官方文档也说的不大清楚,如果Attribute没有受到GameplayEffects的影响时,这两个值其实是相同的。而受到GameplayEffects影响时,如果是一次性的修改,则直接修改的时候BaseValue,CurrentValue也会跟着改变,两个值的结果相同。如果影响是时效性的,比如一段时间内提高移动速度,那么,GameplayEffects修改的是CurrentValue的值。
定义AttributeSet属性
AttributeSetBase.h
// 版权归暮志未晚所有。
#pragma once
#include "CoreMinimal.h"
#include "AttributeSet.h"
#include "AbilitySystemComponent.h"
#include "AttributeSetBase.generated.h"
// Uses macros from AttributeSet.h
#define ATTRIBUTE_ACCESSORS(ClassName, PropertyName) \
GAMEPLAYATTRIBUTE_PROPERTY_GETTER(ClassName, PropertyName) \
GAMEPLAYATTRIBUTE_VALUE_GETTER(PropertyName) \
GAMEPLAYATTRIBUTE_VALUE_SETTER(PropertyName) \
GAMEPLAYATTRIBUTE_VALUE_INITTER(PropertyName)
/**
*
*/
UCLASS()
class AURA_API UAttributeSetBase : public UAttributeSet
{
GENERATED_BODY()
public:
UAttributeSetBase();
virtual void GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const override;
UPROPERTY(BlueprintReadOnly,ReplicatedUsing = OnRep_Health, Category="Vital Attributes")
FGameplayAttributeData Health;
ATTRIBUTE_ACCESSORS(UAttributeSetBase, Health);
UPROPERTY(BlueprintReadOnly,ReplicatedUsing = OnRep_MaxHealth, Category="Vital Attributes")
FGameplayAttributeData MaxHealth;
ATTRIBUTE_ACCESSORS(UAttributeSetBase, MaxHealth);
UFUNCTION()
void OnRep_Health(const FGameplayAttributeData& OldHealth) const;
UFUNCTION()
void OnRep_MaxHealth(const FGameplayAttributeData& OldMaxHealth) const;
};
AttributeSetBase.cpp
// 版权归暮志未晚所有。
#include "AbilitySystem/AttributeSetBase.h"
#include "Net/UnrealNetwork.h"
UAttributeSetBase::UAttributeSetBase()
{
InitHealth(100.f);
InitMaxHealth(100.f);
InitMana(100.f);
InitMaxMana(100.f);
}
void UAttributeSetBase::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const
{
Super::GetLifetimeReplicatedProps(OutLifetimeProps);
DOREPLIFETIME_CONDITION_NOTIFY(UAttributeSetBase, Health, COND_None, REPNOTIFY_Always);
DOREPLIFETIME_CONDITION_NOTIFY(UAttributeSetBase, MaxHealth, COND_None, REPNOTIFY_Always);
}
void UAttributeSetBase::OnRep_Health(const FGameplayAttributeData& OldHealth) const
{
GAMEPLAYATTRIBUTE_REPNOTIFY(UAttributeSetBase, Health, OldHealth);
}
void UAttributeSetBase::OnRep_MaxHealth(const FGameplayAttributeData& OldMaxHealth) const
{
GAMEPLAYATTRIBUTE_REPNOTIFY(UAttributeSetBase, MaxHealth, OldMaxHealth);
}
在上面的代码中,我创建了两个属性,一个是Health,用来表示角色的当前血量,另一个是MaxHealth,代表角色的最大血量。
宏的设置,编译时会默认给变量生成相应的Getter以及Setter函数,当前设置会生成四个函数,获取属性,获取值,设置值,以及初始化值。
变量的OnRep 函数调用GAMEPLAYATTRIBUTE_REPNOTIFY 宏才能使用预测系统
Attribute 需要被添加到GetLifetimeReplicatedProps中,COND_None 为触发没有条件限制,REPTNOTIFY_Always 告诉 OnRep 方法在本地值和服务器下发的值即使已经相同也会触发(为了预测),默认情况下OnRep不会触发
如果只是做单机,不需要与服务器同步复制,那么OnRep 和GetLifetimeReplicatedProps可以被跳过。
验证属性
运行游戏,按一下~,输入showdebug abilitysystem。
在最上面一行,显示当前控制角色的AvatarActor和OwnerActor。
我们还可以通过Page Up和Page Down按钮切换查看目标。
在左下角,则可以查看到我们修改的属性的数值。