UE的GAS学习过程
参考文档:https://github.com/BillEliot/GASDocumentation_Chinese
GAS即GameplayAbilitySystem,其核心为AbilitySystemComponent组件。
其实现由技能系统组件(AbilitySystemComponent),调用技能(Ability),技能中实现具体逻辑,由效果(Effect)对其属性(Attribute)进行修改。
开始
UCLASS()
class ABILTYDEMO_API AMyCharacter : public ACharacter, public IAbilitySystemInterface
{
GENERATED_BODY()
public:
// Sets default values for this character's properties
AMyCharacter();
UPROPERTY()
UAbilitySystemComponent* AbilitySystemComponent;
UPROPERTY()
UMyAttributeSet* AbilitySet;
UPROPERTY(BlueprintReadWrite,EditAnywhere,Category="Ability")
TSubclassOf<UGameplayAbility> Ability;
protected:
// Called when the game starts or when spawned
virtual void BeginPlay() override;
public:
// Called every frame
virtual void Tick(float DeltaTime) override;
// Called to bind functionality to input
virtual void SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent) override;
virtual class UAbilitySystemComponent* GetAbilitySystemComponent() const override;
};
IAbilitySystemInterface
需要去继承这个借口,并实现virtual class UAbilitySystemComponent* GetAbilitySystemComponent() const override;
方法
同时需要申明UAbilitySystemComponent* AbilitySystemComponent;
而GetAbilitySystemComponent()
返回的对象便是该组件。
对于技能属性UMyAttributeSet* AbilitySet;
会自动加载进AbilitySystemaComponent
中。
技能属性集需要继承UAttributeSet
一下为UMyAttributeSet
类的具体
#define ATTRIBUTE_ACCESSORS(ClassName, PropertyName) \
GAMEPLAYATTRIBUTE_PROPERTY_GETTER(ClassName, PropertyName) \
GAMEPLAYATTRIBUTE_VALUE_GETTER(PropertyName) \
GAMEPLAYATTRIBUTE_VALUE_SETTER(PropertyName) \
GAMEPLAYATTRIBUTE_VALUE_INITTER(PropertyName)
UCLASS()
class ABILTYDEMO_API UMyAttributeSet : public UAttributeSet
{
GENERATED_BODY()
public:
UMyAttributeSet();
UPROPERTY(BlueprintReadOnly, Category = "Health", ReplicatedUsing = OnRep_Health)
FGameplayAttributeData Health;
UFUNCTION()
virtual void OnRep_Health(const FGameplayAttributeData& OldHealth);
ATTRIBUTE_ACCESSORS(UMyAttributeSet, Health)
virtual void PostGameplayEffectExecute(const FGameplayEffectModCallbackData& Data) override;
virtual void PreAttributeChange(const FGameplayAttribute& Attribute, float& NewValue) override;
virtual void GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const override;
};
对于上面的宏,在Attribute.h的源码中有解释,其作用是生成对应的GetValue、SetValue、InitValue、GetAttribute方法
/**
* This defines a set of helper functions for accessing and initializing attributes, to avoid having to manually write these functions.
* It would creates the following functions, for attribute Health
*
* static FGameplayAttribute UMyHealthSet::GetHealthAttribute();
* FORCEINLINE float UMyHealthSet::GetHealth() const;
* FORCEINLINE void UMyHealthSet::SetHealth(float NewVal);
* FORCEINLINE void UMyHealthSet::InitHealth(float NewVal);
*
* To use this in your game you can define something like this, and then add game-specific functions as necessary:
*
* #define ATTRIBUTE_ACCESSORS(ClassName, PropertyName) \
* GAMEPLAYATTRIBUTE_PROPERTY_GETTER(ClassName, PropertyName) \
* GAMEPLAYATTRIBUTE_VALUE_GETTER(PropertyName) \
* GAMEPLAYATTRIBUTE_VALUE_SETTER(PropertyName) \
* GAMEPLAYATTRIBUTE_VALUE_INITTER(PropertyName)
*
* ATTRIBUTE_ACCESSORS(UMyHealthSet, Health)
*/
#define GAMEPLAYATTRIBUTE_PROPERTY_GETTER(ClassName, PropertyName) \
static FGameplayAttribute Get##PropertyName##Attribute() \
{ \
static FProperty* Prop = FindFieldChecked<FProperty>(ClassName::StaticClass(), GET_MEMBER_NAME_CHECKED(ClassName, PropertyName)); \
return Prop; \
}
#define GAMEPLAYATTRIBUTE_VALUE_GETTER(PropertyName) \
FORCEINLINE float Get##PropertyName() const \
{ \
return PropertyName.GetCurrentValue(); \
}
#define GAMEPLAYATTRIBUTE_VALUE_SETTER(PropertyName) \
FORCEINLINE void Set##PropertyName(float NewVal) \
{ \
UAbilitySystemComponent* AbilityComp = GetOwningAbilitySystemComponent(); \
if (ensure(AbilityComp)) \
{ \
AbilityComp->SetNumericAttributeBase(Get##PropertyName##Attribute(), NewVal); \
}; \
}
#define GAMEPLAYATTRIBUTE_VALUE_INITTER(PropertyName) \
FORCEINLINE void Init##PropertyName(float NewVal) \
{ \
PropertyName.SetBaseValue(NewVal); \
PropertyName.SetCurrentValue(NewVal); \
}
现在已经有了技能组件和技能属性,接下来尝试让他去执行技能。
UCLASS()
class ABILTYDEMO_API UMyGameplayAbility : public UGameplayAbility
{
GENERATED_BODY()
public:
UMyGameplayAbility();
UPROPERTY(EditAnywhere,BlueprintReadWrite)
TSubclassOf<UGameplayEffect> Effect;
virtual void ActivateAbility(const FGameplayAbilitySpecHandle Handle, const FGameplayAbilityActorInfo* ActorInfo, const FGameplayAbilityActivationInfo ActivationInfo, const FGameplayEventData* TriggerEventData) override;
protected:
virtual void EndAbility(const FGameplayAbilitySpecHandle Handle, const FGameplayAbilityActorInfo* ActorInfo,
const FGameplayAbilityActivationInfo ActivationInfo, bool bReplicateEndAbility, bool bWasCancelled) override;
};
技能需要继承UGameplayAbility
对其ActivateAbility
进行重写,在里面实现具体的逻辑
void UMyGameplayAbility::ActivateAbility(const FGameplayAbilitySpecHandle Handle,
const FGameplayAbilityActorInfo* ActorInfo, const FGameplayAbilityActivationInfo ActivationInfo,
const FGameplayEventData* TriggerEventData)
{
Super::ActivateAbility(Handle, ActorInfo, ActivationInfo, TriggerEventData);
UE_LOG(LogTemp, Log, TEXT("play Ability In Ability"));
ApplyGameplayEffectSpecToOwner(Handle, ActorInfo, ActivationInfo, MakeOutgoingGameplayEffectSpec(Effect));//激活技能
}
如何调用技能
GameplayAbilitySpecHandle = AbilitySystemComponent->GiveAbility(Ability.GetDefaultObject());//对技能组件授予技能
AbilitySystemComponent->TryActivateAbility(GameplayAbilitySpecHandle);//激活系统技能
系统激活技能是会自动调用ActivateAbility
以及EndAbility
Effect
为技能效果,基于配置,由蓝图来写,继承GamePlayEffect
,这东西下次再讲。
将该类引用传入C++进行调用,主要是修改系统组件具备的属性。