LoginSignup
1
0

[UE] Gameplay Ability System ※ メモ

Last updated at Posted at 2023-12-25

プラグインの有効化

キャプチャ.jpg

タグの追加

キャプチャ.jpg

モジュールの追加

SampleProject.build.cs
PublicDependencyModuleNames.AddRange(new string[] { "GameplayAbilities", "GameplayTags", "GameplayTasks" });

スタートアップ処理

SampleProject.cpp
#include "Interfaces/IPluginManager.h"
#include "Modules/ModuleManager.h"
#include "AbilitySystemGlobals.h"
#include "GameplayTagsManager.h"

class FSampleGameModule : public FDefaultGameModuleImpl
{
public:
    virtual void StartupModule() override
    {
        check(LoadTagIni("Config/Tags"));
        
        auto& AbilitySystem = UAbilitySystemGlobals::Get();
        if ( ! AbilitySystem.IsAbilitySystemGlobalsInitialized())
        {
            /* システムの初期化 */
            AbilitySystem.InitGlobalData();
        }
    }

private:
    bool LoadTagIni(const FString& Directory)
    {
        if (const auto ThisPlugin = IPluginManager::Get().FindPlugin(TEXT("CommonConversation")))
        {
            /* GameplayTag 用の .ini ファイル配置ディレクトリパスを登録する */
            UGameplayTagsManager::Get().AddTagIniSearchPath(ThisPlugin->GetBaseDir() / *Directory);
            return true;
        }
        return false;
    }
};
IMPLEMENT_PRIMARY_GAME_MODULE(FSampleGameModule, SampleProject, "SampleProject");

AttributeSet の継承クラス

SampleAttributeSet.h
#include "AttributeSet.h"
#include "AbilitySystemComponent.h"
#include "Net/UnrealNetwork.h"
#include "GameplayEffectAggregatorLibrary.h"

/* Attribute の Getter & Setter 関数の自動生成マクロ */
#define ATTRIBUTE_ACCESSORS(ClassName, PropertyName) \
        GAMEPLAYATTRIBUTE_PROPERTY_GETTER(ClassName, PropertyName) \
        GAMEPLAYATTRIBUTE_VALUE_GETTER(PropertyName) \
        GAMEPLAYATTRIBUTE_VALUE_SETTER(PropertyName) \
        GAMEPLAYATTRIBUTE_VALUE_INITTER(PropertyName)

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

public:
    UFUNCTION()
    virtual void OnRep_SampleValue(const FGameplayAttributeData& OldValue)
    {
        GAMEPLAYATTRIBUTE_REPNOTIFY(USampleAttributeSet, SampleValue, OldValue);
    }

public: /* UObject interface */
    /* 生存中に複製されるプロパティを返す */
    virtual void GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const override
    {
        Super::GetLifetimeReplicatedProps(OutLifetimeProps);
        DOREPLIFETIME_CONDITION_NOTIFY(USampleAttributeSet, SampleValue, COND_None, REPNOTIFY_Always);
    }
    
public: /* UAttributeSet interface */
    /* CurrentValue の変更が行われる直前に呼ばれるクランプ処理などを行う関数 */
    virtual void PreAttributeChange(const FGameplayAttribute& Attribute, float& NewValue) override
    {
        if (Attribute == GetSampleValueAttribute())
        {
	        NewValue = FMath::Clamp(NewValue, 0.0f, 100.0f);
        }
    }
    
    /* GameplayEffect から BaseValue の変更が行われた際に呼ばれる */
    virtual void PostGameplayEffectExecute(const struct FGameplayEffectModCallbackData& Data) override
    {
        Super::PostGameplayEffectExecute(Data);
    }
    
    /* Aggregator 生成時に呼ばれる */
    virtual void OnAttributeAggregatorCreated(const FGameplayAttribute& Attribute, FAggregator* NewAggregator) const override
    {
        if (NewAggregator != nullptr)
        {
            if (Attribute == GetSampleValueAttribute())
            {
                /* 最も否定的な Modifier とすべての肯定的な Modifier のみを許可する */
                NewAggregator->EvaluationMetaData = &FAggregatorEvaluateMetaDataLibrary::MostNegativeMod_AllPositiveMods;
            }
        }
    }

public:
    UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Sample", ReplicatedUsing = OnRep_SampleValue)
    FGameplayAttributeData SampleValue{ 100.0f };
    ATTRIBUTE_ACCESSORS(USampleAttributeSet, SampleValue) /* 初期化関数の自動生成マクロ */
};

Ability System を保持するクラス

SampleCharacter.h
#include "Abilities/GameplayAbility.h"
#include "AbilitySystemInterface.h"
#include "AbilitySystemComponent.h"
#include "GameplayTags.h"
#include "GameplayEffectTypes.h"

UCLASS()
class ASampleCharacter : public ACharacter,
                       , public IAbilitySystemInterface
                       , public IGameplayTagAssetInterface
{
    GENERATED_BODY()
    
public:
    ASampleCharacter(const FObjectInitializer& ObjectInitializer)
    {
        AbilitySystemComponent = CreateDefaultSubobject<UAbilitySystemComponent>(TEXT("Ability System"));
        AbilitySystemComponent->SetIsReplicated(true);
        AbilitySystemComponent->SetReplicationMode(EGameplayEffectReplicationMode::Full);
        AbilitySystemComponent->RegisterGenericGameplayTagEvent().AddUObject(this, &ASampleCharacter::OnAbilitySystemGenericGameplayTagEvent);
        
        /* UAbilitySystemComponent に自動登録 */
        SampleAttributeSet = CreateDefaultSubobject<USampleAttributeSet>(TEXT("AbilitySet"));
        
        GameplayTagCountContainer.RegisterGenericGameplayEvent().AddUObject(this, &ASampleCharacter::OnGameplayTagCounterGenericGameplayTagEvent);
    }

public: /* UObject */
    virtual void BeginPlay() override
    {
        Super::BeginPlay();

        if (auto ThisComponent = GetAbilitySystemComponent())
        {
            int32 Index = 0;
            for (auto& GameplayAbiliity : StartupGameplayAbiliities)
            {
                if (IsValid(GameplayAbiliity.GetGCPtr()))
                {
                    ThisComponent->GiveAbility(FGameplayAbilitySpec(GameplayAbiliity, 1, Index++));
                }
            }
	        
            ThisComponent->InitAbilityActorInfo(this, this);
        }
    }

public: /* APawn interface */
    /* 所有された際に呼ばれる */
    virtual void PossessedBy(AController* NewController) override
    {
        Super::PossessedBy(NewController);

        if (auto ThisComponent = GetAbilitySystemComponent())
        {
	        ThisComponent->RefreshAbilityActorInfo();

	        if (ThisComponent->ReplicationMode == EGameplayEffectReplicationMode::Mixed)
	        {
		        SetOwner(NewController);
	        }
        }
    }
    
public: /* IAbilitySystemInterface */
    /* UAbilitySystemComponent の取得 */
    virtual UAbilitySystemComponent* GetAbilitySystemComponent() const override
    {
        return AbilitySystemComponent;
    }
    
public: /* IGameplayTagAssetInterface */
    /* 所有している GameplayTag の取得 */
    virtual void GetOwnedGameplayTags(FGameplayTagContainer& TagContainer) const override
    {
        for (const auto& GameplayTag : GameplayTagContainer.GetGameplayTagArray())
        {
	        if ( ! TagContainer.HasTag(GameplayTag))
	        {
		        TagContainer.AddTag(GameplayTag);
	        }
        }
    }

public:
    /* UAttributeSet 追加 */
    bool AddAttributeSet(UAttributeSet* Attribute)
    {
        if (IsValid(Attribute))
        {
            if (auto ThisComponent = GetAbilitySystemComponent())
            {
                ThisComponent->AddSpawnedAttribute(Attribute);
                ThisComponent->ForceReplication();
                return true;
            }
        }
        return false;
    }
    
    /* UAttributeSet 削除 */
    void RemoveAttributeSet(UAttributeSet* Attribute)
    {
        if (IsValid(Attribute))
        {
            if (auto ThisComponent = GetAbilitySystemComponent())
            {
                ThisComponent->RemoveSpawnedAttribute(Attribute);
                ThisComponent->ForceReplication();
            }
        }
    }
    
    /* サンプル値の設定 */
    bool SetAttributeSampleValue(const float& Value)
    {
        if (IsValid(SampleAttributeSet))
        {
            if (auto ThisComponent = GetAbilitySystemComponent())
            {
                ThisComponent->SetNumericAttributeBase(USampleAttributeSet::GetSampleValueAttribute(), Value);
                return true;
            }
        }
        return false;
    }
    
    /* サンプル値の取得 */
    float GetAttributeSampleValue() const
    {
        if (IsValid(SampleAttributeSet))
        {
            if (auto ThisComponent = GetAbilitySystemComponent())
            {
                return ThisComponent->GetNumericAttribute(USampleAttributeSet::GetSampleValueAttribute());
            }
        }
        return 0.0f;
    }

private:
    /* GameplayTag 参照カウントが更新された際に呼ばれる */
    void OnAbilitySystemGenericGameplayTagEvent(const FGameplayTag GameplayTag, int32 NewCount)
    {
        if ( ! GameplayTagContainer.HasTag(GameplayTag))
        {
	        GameplayTagContainer.AddTag(GameplayTag);
        }
        
        if ( ! GameplayTagCountContainer.HasMatchingGameplayTag(GameplayTag))
        {
	        GameplayTagCountContainer.SetTagCount(GameplayTag, NewCount);
        }
        else
        {
	        static_cast<void>(GameplayTagCountContainer.UpdateTagCount(GameplayTag, (NewCount - GameplayTagCountContainer.GetTagCount(GameplayTag))));
        }
    }
    
    /* GameplayTag のカウントが 0 になった際に呼ばれる */
    void OnGameplayTagCounterGenericGameplayTagEvent(const FGameplayTag GameplayTag, int32 NewCount)
    {
        if (NewCount <= 0)
        {
	        GameplayTagContainer.RemoveTag(GameplayTag);
        }
    }
    
public:

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Abilities)
	TArray<TSubclassOf<UGameplayAbility>> StartupGameplayAbiliities;
    
private:
    UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Sample", meta = (AllowPrivateAccess = "true"))
    TObjectPtr<USampleAttributeSet> SampleAttributeSet{ nullptr };
    
    UPROPERTY(BlueprintReadOnly, VisibleAnywhere, Category = Abilities, meta = (AllowPrivateAccess = "true"))
    TObjectPtr<UAbilitySystemComponent> AbilitySystemComponent{ nullptr };
    
    UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Sample", meta = (AllowPrivateAccess = "true", Categories = "GameplayCue"))
    FGameplayTagContainer GameplayTagContainer;
    
    FGameplayTagCountContainer GameplayTagCountContainer;
};

アニメーションモンタージュの作成

キャプチャ.jpg

Gameplay Effect BP の作成

キャプチャ.jpg
※ BaseValue、CurrentValue ともに影響する。

Gameplay Ability BP の作成

キャプチャ.jpg
※ 実行すると AbilityTag を付与する。

Gameplay Ability の実行

キャプチャ.jpg

参考資料

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0