やあ
GameplayEffectExectuionCalculation
についてのメモ
以下GEEC
と略します。
間違ってるところなどあれば教えてください。
目次
- やあ
- 目次
- キャプチャするAttribute
- Attributeをキャプチャする対象
- キャプチャするAttributeをスナップショットするかどうか
- 実装の話
- キャプチャしたAttributeに処理結果を適用する
キャプチャする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
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
キャプチャする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のまま計算されます。
実装の話
キャプチャした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
画像.6
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
の元の値とModifierMagnitude
をModifierOp
で処理した結果の値。
例
キャラクターの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
部分です。