現在設定しているキャラクターのアビリティではアニメーションモンタージュの再生とウェイトを行ってますが、それ以外にもHP,MPなどのパラメータ変更を担うエフェクト(GameplayEffect)、エフェクトに伴って画面上にパーティクルなどの演出を表示するキュー(GameplayCue)、特定のイベント(GameplayEvent)が発生したときにコールバックを受けて処理行うタスク(GameplayTask)を実行することができます。
今回は、まずキャラクターのHP、MPや移動速度といったパラメータのセットであるアトリビュートセットを定義し、アビリティの使用によりそのアトリビュートセットに変更を加えるエフェクトを実行してみたいと思います。
まずアトリビュートセットに最大ヒットポイント、ヒットポイント、移動スピード、ダメージの4つのパラメータを定義します。C++での作成となるのでコンテンツブラウザのコンテンツ→C++クラス→GPA内で右クリックし新規C++クラスを指定します。
親クラスは、全てのクラスを表示にチェックを入れ検索でAttributeSetを指定します。
名前はGPAAttributeSetという名称にして「クラスを作成」をクリックします
次にソースの修正ですが、今回はフルリストを掲載します。
[GPAAttributeSet.h]
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "AttributeSet.h"
#include "AbilitySystemComponent.h"
#include "GPAAttributeSet.generated.h"
// AttributeSet.hで紹介されているアトリビュートへのSetter,Getter定義マクロ
#define ATTRIBUTE_ACCESSORS(ClassName, PropertyName) \
GAMEPLAYATTRIBUTE_PROPERTY_GETTER(ClassName, PropertyName) \
GAMEPLAYATTRIBUTE_VALUE_GETTER(PropertyName) \
GAMEPLAYATTRIBUTE_VALUE_SETTER(PropertyName) \
GAMEPLAYATTRIBUTE_VALUE_INITTER(PropertyName)
/**
*
*/
UCLASS()
class GPA_API UGPAAttributeSet : public UAttributeSet
{
GENERATED_BODY()
public:
// 初期値設定用コンストラクタ定義
UGPAAttributeSet();
// Blueprintアクセス可能としたMaxHealth定義、ATTRIBUTE_ACCESSORSによるアクセサ追記
UPROPERTY(Category = "GPAAttributes", EditAnywhere, BlueprintReadWrite)
FGameplayAttributeData MaxHealth;
ATTRIBUTE_ACCESSORS(UGPAAttributeSet, MaxHealth);
FGameplayAttribute MaxHealthAttribute(); // アトリビュート型取得関数
// Blueprintアクセス可能としたHealth定義、ATTRIBUTE_ACCESSORSによるアクセサ追記
UPROPERTY(Category = "GPAAttributes", EditAnywhere, BlueprintReadWrite)
FGameplayAttributeData Health;
ATTRIBUTE_ACCESSORS(UGPAAttributeSet, Health);
FGameplayAttribute HealthAttribute(); // アトリビュート型取得関数
// Blueprintアクセス可能としたMaxSpeed定義、ATTRIBUTE_ACCESSORSによるアクセサ追記
UPROPERTY(Category = "GPAAttributes", EditAnywhere, BlueprintReadWrite)
FGameplayAttributeData MaxSpeed;
ATTRIBUTE_ACCESSORS(UGPAAttributeSet, MaxSpeed);
FGameplayAttribute MaxSpeedAttribute(); // アトリビュート型取得関数
// Blueprintアクセス可能としたダメージ定義、ATTRIBUTE_ACCESSORSによるアクセサ追記
UPROPERTY(Category = "GPAAttributes", EditAnywhere, BlueprintReadWrite)
FGameplayAttributeData Damage;
ATTRIBUTE_ACCESSORS(UGPAAttributeSet, Damage);
FGameplayAttribute DamageAttribute(); // アトリビュート型取得関数
/** エフェクトによりアトリビュートが変化した場合のPost処理。主にUE4で直接管理しているメンバへの書き戻しを行う */
virtual void PostGameplayEffectExecute(const FGameplayEffectModCallbackData& Data) override;
};
大枠でいうと、ヘッダではアトリビュートとしてMaxHealth,Health,MaxSpeedを定義して、アクセッサを用意しています。cppファイルではコンストラクタで初期値を与え、変数ごとにアトリビュート型を取得する関数を用意します。
またPostGameEffectExecute関数は、アトリビュート値を変更するエフェクト(GameplayEffect)が実行されたときに、その変更されたアトリビュート値をGPACharacterクラスに書き戻す用に呼び出される関数です。今回の場合は、最大スピードが変更された際、GPACharacter::HandleMaxSpeedChanged関数を呼び出していますが、この関数の中ではGPACharacterが保持しているCharacterMovementComponentのMaxSpeedを書き換える予定です。ですが、現在はこの関数は定義されていないので、このままだとコンパイルが通りませんので、次にGPACharacter側のソースに変更を加えます。
アトリビュート変更をCharacterへ反映
〇GPACharacter.hの変更
〇GPACharacter.cppの変更
- アトリビュートセットの実体を生成
AGPACharacterのコンストラクタでアトリビュートセットの実体を生成してヘッダで定義したAttributeSetのポインタに設定します。
// create the attribute set
AttributeSet = CreateDefaultSubobject<UGPAAttributeSet>(TEXT("AttributeSet"));
-
以下のソースをファイルの最後に加えて、アトリビュートのMaxSpeedが書き換わった時にCharacterMovementのMaxWalkSpeedを書き換える関数の実体を定義します。この関数は先ほど作成したGPAAttributeSet.cppのPostGameplayEffectExecute関数から呼び出されます。
void AGPACharacter::HandleMaxSpeedChanged(float DeltaValue, const struct FGameplayTagContainer& EventTags)
{
GetCharacterMovement()->MaxWalkSpeed = AttributeSet->GetMaxSpeed();
}
書き換えたら、ここで一旦コンパイルします。
ここまで来たら、上記を反映させるために一旦エディタを再起動しておきましょう。
エフェクトの作成
次に、アトリビュートを書き換えるエフェクトを作成します。
コンテンツブラウザのコンテンツ→Abilitiesの中で右クリックしてブループリントクラスを選択。
親クラスはGameplayEffectを選びます。
作ったクラスはGE_MaxSpeedHighとします。
GE_MaxSpeedHighをダブルクリックして詳細を確認してください。
ここで変更するアトリビュートに関しての設定を粉います。
Modifiersで+して1項目追加し、0の項目を開いて以下の設定を行います。
- AttributeはGPAAttributeSet.MaxSpeed
設定するアトリビュートはMaxSpeed
- Modifier OpはOverride
変更方式は指定値で上書き(ちなみにAddを選ぶと以前の値に加算になります)
- Modifier Magnitude→MagnitudeCalculationTypeはScalableFloat
変更時の計算はFloat値を使う
- Modifier Magnitude→ScalableFloatMagnitudeは1200
設定値は1200
これで、このエフェクトを実行すると最大移動スピードが1200になります。
この状態でコンパイル・保存して閉じてください。
次に、GE_MaxSpeedHighをコピーしてGE_MaxSpeedNormalを作成し
ScalableFloatMagnitudeを600にしてコンパイル・保存しましょう。
さて、これで最大スピードを変更するエフェクトができたので、これを実行するアビリティを作成します。
アビリティの作成
移動速度をアップするアビリティを作成します。
コンテンツブラウザのコンテンツ→Abilitiesの中で右クリックしてブループリントクラスを選択
親クラスはGameplayAbilityとします。
作ったアビリティはGA_Dashとします。
このGA_DashをダブルクリックしてBPを開き、クラスのデフォルトでタグの設定を
このようにAbility TagsはAbility.Action.Dash、BlockAbilitiesWithTagは、Ability.Actionと指定し、ほかのアビリティと排他して動作するように指定します。
次にブループリントを編集します。
上記のようにActivateAbilityからいつものCommitAbilityして、自分へエフェクトを実行するApplyGameplayEffectToOwnerを呼び出します。このときGameplayEffectClassには先ほど作った"GE_MaxSpeedHigh"を指定します。その後5秒ウェイトしアビリティ終了です。
OnEndAbilityでは移動速度を通常に戻すためApplyGameplayEffectToOwnerで"GE_MaxSpeedNormal"を指定しています。
アビリティの登録と呼び出し
次にキャラクター側にアビリティを登録します。
BP_BPchanを開いて、クラスのデフォルトを指定し、詳細のAbilitiesにGA_Dashを追加しましょう。
最後にキーを押されたらアビリティを呼び出すノードを追加します。
BP_BPchanのイベントグラフで、他のアビリティ呼び出しと同様に3キーが押されたらGA_Dashが呼ばれるようにしておきます。
これで設定は完了です。プレイして3キーを押すとスピードが上り、5秒後に元に戻るか確認しましょう。
キュー(GameplayCue)
最後にパーティクルや演出を表示するキューについて軽く触れておきましょう。
エフェクトはHP回復やダメージを与えるなど、アトリビュートの値を変更するために使われますが、それに伴って画面上に演出を出したいケースは多いはずです。
そんなときに使われるのがこのキューです。
今回、スピードアップのエフェクトを作りましたが、それに伴って表示されるキューを作ってみましょう。
いつものようにコンテンツブラウザのAbilitiesの中で右クリックし”基本アセットを作成”の中にあるブループリントクラスを選びます。親クラスはGameplayCueNofify_Actorとして選択を押します。
作ったアセットの名前はGC_DashEffectとしておきましょう。
GC_DashEffectをダブルクリックし「フルブループリンタを開く」を選んで、ブループリントエディタを開いてください。
以下のようにBeginPlayからアクターの位置にEmitterを発生させてアクターは削除します(EmitterはAutoDestoryにチェックが入ってるので再生後自動削除)
今回再生させるパーティクルはスターターコンテンツにあるP_Explosionとします。
次に、クラスのデフォルトを選択し、詳細の中のGameplayCueで、GameplayCueTagを"Effect.Dash"としておきます。
次に、GE_MaxSpeedHigh側でキューを発生させる設定を行います。
GE_MaxSpeedHighをダブルクリックしてクラスのデフォルトを表示し、
Display項目のGameplay Cuesを+して項目を追加し、GameplayCueTagsに先ほどのEffect.Dashを設定します。
これによりこのエフェクトが発生したときにEffect.Dashのタグが付いているキューが自動的に生成されるようになります。
これで準備は完了です。すべて保存してプレイで開始してダッシュしてみてください。
上手くいっていればこんな感じでブループリントちゃんに爆発エフェクトが発生すると思います。
なお、今回はエフェクト発生時にエフェクトを1回発生させる作りになっていますが、GameplayEffectをInstantではなくHasDurationで効果時間を持たせればエフェクト実行中の間パーティクルを表示し続けるなどの演出が可能です。パーティクルは特定のソケットに張り付けることもできるので、魔法キャスト中、エネルギーが手に集中していくようなエフェクトを出すといったこともできます。