UE4 C++ GameplayAbilitySystemを勉強していくPart.3-4 GameplayEffectExectuionCalculation

やあ

GameplayEffectExectuionCalculationについてのメモ
以下GEECと略します。
間違ってるところなどあれば教えてください。

f:id:pto8913:20210126112658p:plain

目次

キャプチャするAttribute

キャプチャするAttributeの宣言

今回はほぼすべてのゲームにある、最大HPをキャプチャしてみる。
まず、キャプチャしたいすべてのAttributeを宣言するための構造体の作成。
GEEC_Test.h

// Copyright(C)write by pto8913. 2020. All Rights Reserved.

#pragma once

#include "CoreMinimal.h"
#include "GameplayEffectExecutionCalculation.h"
#include "GEEC_Test.generated.h"

UCLASS()
class TESTPROJECT_API UGEEC_Test : public UGameplayEffectExecutionCalculation
{
    GENERATED_BODY()
};

GEEC_Test.cpp

// Copyright(C)write by pto8913. 2020. All Rights Reserved.

#include "Abilities/GEEC_Test.h"

struct TestStatics {
    /* キャプチャしたいAttributeの宣言 */
    DECLARE_ATTRIBUTE_CAPTUREDEF(MaxHealth);

    /* コンストラクタ */
    TestStatics()
    {
        /* 
       @ param1 : UTestAttributeSet : 自分で作ったAttributeSetクラスを指定 
       @ param2 : MaxHealth : UTestAttributeSet内にあるキャプチャしたいAttributeの名前。上で宣言したものと同じ名前
       @ param3 : Source : キャプチャする対象。あとで説明します。
       @ param4 : true : スナップショットするかどうか。あとで説明します
       */
        DEFINE_ATTRIBUTE_CAPTUREDEF(UTestAttributeSet, MaxHealth, Source, true);
    }
};

static const TestStatics& Test()
{
    static TestStatics test;
    return test;
}

キャプチャするAttributeをGEECの内部で処理できるようにする(超大事)

GEECのコンストラクタで、
RelevantAttributesToCaptureにキャプチャするAttributeを追加することで、内部から値を処理できるようになる。

InvalidScopedModifierAttributesに追加すると、値のキャプチャはできるけど、エディタから処理もできないし、値も処理できないようになる。
と思ってたのですがどうもちがうっぽい

これを忘れて、値が変わらないよーって泣くことにならないように覚えておく。

GEEC_Test.hに追加

/* コンストラクタ */
GEEC_Test();

GEEC_Test.cppに追加

UGEEC_Test::UGEEC_Test()
{
    /* 宣言したAttributeをエディタに公開する画像.2参照 */
    RelevantAttributesToCapture.Add(Test().MaxHealthDef);
    /* 宣言だけしてエディタに公開しない */
    // InvalidScopedModifierAttributes.Add(Test().MaxHealthDef);
}

画像.2 f:id:pto8913:20210126114548j:plain

RelevantAttributesToCaptureに追加することで画像.2の赤枠内に追加される。

目次に戻る

Attributeをキャプチャする対象

TestStaticsのコンストラクタのparam3部分

/* コンストラクタ */
TestStatics()
{
    /* 
   @ param1 : UTestAttributeSet : 自分で作ったAttributeSetクラスを指定 
   @ param2 : MaxHealth : UTestAttributeSet内にあるキャプチャしたいAttributeの名前。上で宣言したものと同じ名前
   @ param3 : Source : キャプチャする対象。
   @ param4 : true : スナップショットするかどうか。あとで説明します
   */
    DEFINE_ATTRIBUTE_CAPTUREDEF(UTestAttributeSet, MaxHealth, Source, true);
}

このparam3でキャプチャする対象を選択する。
マクロで隠されているけど、実際はEGameplayEffectAttributeCaptureSource::Sourceという列挙体で、
EGameplayEffectAttributeCaptureSource::Source
EGameplayEffectAttributeCaptureSource::Target
の二つがある。

EGameplayEffectAttributeCaptureSource::Source

これは、このGEECを持つGameplayEffectの実行者です。
例1.
プレイヤーが攻撃して、敵にダメージを与えるGameplayEffectの実行者はプレイヤーになる。
画像.3参照

例2.
ゲーム開始時に、キャラクターのステータスを決定するGameplayEffectの実行者はそのキャラクター自身になる。

EGameplayEffectAttributeCaptureSource::Target

これは、このGEECを持つGameplayEffectを適用するターゲットのことです。
プレイヤーが攻撃して、敵にダメージを与えるGameplayEffectを適用されるのは、敵なので、ターゲットは敵になる。
画像.3参照

例2.
ゲーム開始時に、キャラクターのステータスを決定するGameplayEffectのターゲットはそのキャラクター自身になる。

画像.3 f:id:pto8913:20210126120545p:plain

目次に戻る

キャプチャするAttributeをスナップショットするかどうか

正直スナップショットについては認識があってるかわからないです。間違ってたらごめんなさい

キャプチャするAttribute
TestStaticsのコンストラクタのparam4部分

/* コンストラクタ */
TestStatics()
{
    /* 
   @ param1 : UTestAttributeSet : 自分で作ったAttributeSetクラスを指定 
   @ param2 : MaxHealth : UTestAttributeSet内にあるキャプチャしたいAttributeの名前。上で宣言したものと同じ名前
   @ param3 : Source : キャプチャする対象。
   @ param4 : true : スナップショットするかどうか。
   */
    DEFINE_ATTRIBUTE_CAPTUREDEF(UTestAttributeSet, MaxHealth, Source, true);
}

このparam4でスナップショットするかどうかを決める。

このGEECを持つGameplayEffectのスペックGameplayEffectSpecを作成した瞬間に、キャプチャしたAttributeを保持するかどうか。


キャラクターが火の玉の魔法を、敵に向けて発射した場合。

理由 :
火の玉を発射した時に魔法攻撃力が5だったが、火の玉が敵に当たった時には、キャラクターの魔法攻撃力が10になっていた場合に、敵が受けるダメージは5であるはずが、10になるのを防ぐためです。

スナップショットをすると、キャラクターが魔法を使ったときに、魔法攻撃力が5なら、敵に魔法が当たる前に魔法攻撃力が変化しても、敵に魔法が当たった時には、魔法攻撃力が5のまま計算されます。
f:id:pto8913:20210126123458p:plain

目次に戻る

実装の話

キャプチャしたAttributeの取得

GEEC_Test.hに追加

virtual void Execute_Implementation(
    const FGameplayEffectCustomExecutionParameters& ExecutionParams,
    OUT FGameplayEffectCustomExecutionOutput& OutExecutionOutput
) const override;

GEEC_Test.cppに追加

void UGEEC_EnemyStatus::Execute_Implementation(
    const FGameplayEffectCustomExecutionParameters& ExecutionParams,
    OUT FGameplayEffectCustomExecutionOutput& OutExecutionOutput
) const
{
    const FGameplayEffectSpec& Spec = ExecutionParams.GetOwningSpec();

    const FGameplayTagContainer* SourceTags = Spec.CapturedSourceTags.GetAggregatedTags();
    const FGameplayTagContainer* TargetTags = Spec.CapturedTargetTags.GetAggregatedTags();

    FAggregatorEvaluateParameters EvaluationParameters;
    EvaluationParameters.SourceTags = SourceTags;
    EvaluationParameters.TargetTags = TargetTags;

    float BaseValue_MaxHealth = 0.f;
    /* ModifierMagnitudeを処理する前の値 */
    ExecutionParams.AttemptCalculateCapturedAttributeBaseValue(TargetSt().MaxHealthDef, BaseValue_MaxHealth);

    float BonusMaxHealth = 0.f;
    /* キャプチャしたAttriuteのModifierMagnitudeの取得 画像.6参照 */
    ExecutionParams.AttemptCalculateCapturedAttributeBonusMagnitude(Test().MaxHealthDef, EvaluationParameters, BonusMaxHealth);

    float MaxHealth = 0.f;
    /* キャプチャしたAttributeの取得 画像.5参照 */
    ExecutionParams.AttemptCalculateCapturedAttributeMagnitude(Test().MaxHealthDef, EvaluationParameters, MaxHealth);
}

画像.5 f:id:pto8913:20210126112850p:plain
画像.6 f:id:pto8913:20210126131250p:plain

AttemptCalculateCapturedAttributeBaseValue

float BaseValue_MaxHealth = 0.f;
ExecutionParams.AttemptCalculateCapturedAttributeBaseValue(TargetSt().MaxHealthDef, BaseValue_MaxHealth);

キャプチャしたAttributeの元の値。


キャラクターのMaxHealth : 100に20追加するGameplayEffectの場合、BaseValueは100になる
キャラクターのHealth : 55に20追加するGameplayEffectの場合、BaseValueは55になる

AttemptCalculateCapturedAttributeBonusMagnitude

float BonusMaxHealth = 0.f;
ExecutionParams.AttemptCalculateCapturedAttributeBonusMagnitude(Test().MaxHealthDef, EvaluationParameters, BonusMaxHealth);

キャプチャしたAttributeに追加されるMagnitudeModifierの値。


キャラクターのMaxHealth : 100に20追加するGameplayEffectの場合、値は20になる

AttemptCalculateCapturedAttributeMagnitude

float MaxHealth = 0.f;
ExecutionParams.AttemptCalculateCapturedAttributeMagnitude(Test().MaxHealthDef, EvaluationParameters, MaxHealth);

キャプチャしたAttributeの元の値とModifierMagnitudeModifierOpで処理した結果の値。


キャラクターのMaxHealth : 100に20追加するGameplayEffectの場合、値は120になる

目次に戻る

キャプチャしたAttributeに処理結果を適用する

GEEC_Test.cppに追加

/*
@param1 : Test().MaxHealthProperty : 処理結果を適用したいAttribute
@param2 : EGameplayModOp::Additive : 処理結果の適用方法
@param3 : MaxHealth : 処理結果の値
*/
OutExecutionOutput.AddOutputModifier(
    FGameplayModifierEvaluatedData(
        Test().MaxHealthProperty,
        EGameplayModOp::Additive,
        MaxHealth
    )
);

適用する対象などはTestStaticsで宣言したものになるので、一番慎重に決めなければいけないのはTestStatics部分です。

目次に戻る