はじめに
Unreal Engine (UE) Advent Calendar 2025 の21日目の記事です!
この記事では Gameplay Tasks について解説します。
この記事での環境は以下の通りです。
- Windows 11
- UE 5.7.1(ランチャー版)
Gameplay Tasks とは
そもそも Gameplay Tasks とは何でしょうか?
一言で表すと「非同期処理を柔軟に管理/制御したり、簡単に自作したりするための仕組み」のことです。
(たぶん)
後で詳しく解説しますが、Gameplay Tasks は UGameplayTask というクラスを継承していくつかの関数をオーバーライドすることで自作することができます。
UGameplayTask を継承したクラスは初めからいくつか用意されていますが、ブループリントで使用できるものでいうと UGameplayTask_WaitDelay や UGameplayTask_SpawnActor、UGameplayTask_ClaimResource などがあります。

これらのノードはいずれも右上に時計のマークが付いていて、Delay や Async Load Asset などの通常の Latent ノードのようにも見えますが、IGameplayTaskOwnerInterface というインターフェースを引数で受け取るという点や、「Async Task」という戻り値でそのクラスのポインタ(Task Wait Delay なら UGameplayTask_WaitDelay*)を返すという点においては通常のものと異なります。
Task Owner 引数に何も指定せずにこれらのノードを使用すると「This blueprint (self) is not a GameplayTaskOwnerInterface, therefore ‘ Task Owner ‘ must have a connection.」というコンパイルエラーが発生します。
(先ほどの3つのノードの中では Claim Resource は除く。)

Task Owner 引数のコンパイルエラーの対処法 ①
エラー文の通り、Task Owner 引数には適切なピンを接続してあげる必要があります。
このコンパイルエラーの対処法は主に3つあります。
1つ目は IGameplayTaskOwnerInterface を実装しているクラスでそれらのノードを使用するという方法です。
例えば APlayerController を親クラスとするブループリントで Gameplay Tasks のノードを使用すると先ほどのコンパイルエラーが発生してしまいますが、AAIController では IGameplayTaskOwnerInterface を実装しているため、そのコンパイルエラーは発生しなくなります。


公式ドキュメントによると、以下の8つのクラスは IGameplayTaskOwnerInterface を実装しています。
- AAIController
- UBTNode
- UGameplayAbility
- UGameplayBehavior
- UGameplayTask
- UGameplayTasksComponent
- UMockGameplayTaskOwner
- UStateTreeComponent
もし、Gameplay Tasks のノードを使用している処理を上記のクラスに移せるようだったら、この方法で対処してもいいかもしれません。
Task Owner 引数のコンパイルエラーの対処法 ②
2つ目は Gameplay Tasks のノードを使用しているアクタに Gameplay Tasks Component をアタッチして、それを Task Owner 引数に渡してあげるという方法です。
この方法ではそのアクタの親クラスを変更する必要もなく、ブループリントだけで完結するので最も手っ取り早い方法かもしれません。

Task Owner 引数のコンパイルエラーの対処法 ③
最後は Gameplay Tasks のノードを使用しているクラスに IGameplayTaskOwnerInterface を実装するという方法です。
この方法では Gameplay Tasks のノードに毎回 Gameplay Tasks Component を渡してあげる必要がなくなりますが、UGameplayTaskOwnerInterface の定義部分では UINTERFACE() に CannotImplementInterfaceInBlueprint という指定子が設定されているのでブループリントでは IGameplayTaskOwnerInterface を実装することができません。
(↓参考:GameplayTaskOwnerInterface.h)
UINTERFACE(MinimalAPI, meta = (CannotImplementInterfaceInBlueprint))
class UGameplayTaskOwnerInterface : public UInterface
{
GENERATED_BODY()
};
なので C++ で IGameplayTaskOwnerInterface を実装する必要があるのですが、その際は {プロジェクト名}.Build.cs に「GameplayTasks」を追加する必要があります。
また、IGameplayTaskOwnerInterface の GetGameplayTasksComponent() と GetGameplayTaskOwner() は PURE_VIRTUAL() で純粋仮想関数として宣言されているので、これらの関数をオーバーライドせずに Gameplay Tasks のノードを使用すると「Pure virtual not implemented~」というメッセージと共にクラッシュします。

なので、自作のクラスに IGameplayTaskOwnerInterface を実装する際は以下のコードのようにしてそれらの純粋仮想関数をオーバーライドしましょう。
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "SampleActor.generated.h"
UCLASS()
class SAMPLE_API ASampleActor : public AActor, public IGameplayTaskOwnerInterface //追加
{
GENERATED_BODY()
public:
ASampleActor();
//追加(コンストラクタでインスタンス化しておく)
UPROPERTY()
TObjectPtr<UGameplayTasksComponent> GameplayTasksComponent;
//追加
virtual UGameplayTasksComponent* GetGameplayTasksComponent(const UGameplayTask& Task) const override
{
return GameplayTasksComponent;
}
//追加
virtual AActor* GetGameplayTaskOwner(const UGameplayTask* Task) const override
{
return const_cast<ASampleActor*>(this);
}
protected:
virtual void BeginPlay() override;
public:
virtual void Tick(float DeltaTime) override;
};
これで Gameplay Tasks のノードの Task Owner 引数に self を渡してもコンパイルエラーが発生せず、ランタイムでもクラッシュしなくなります。
Ability Tasks とは
Gameplay Tasks と似たもので Ability Tasks というものもあります。
Ability Tasks については公式ドキュメントで以下のように説明されています。
アビリティ タスク (C++ クラス UAbilityTask) は、一般的なゲームプレイ タスク クラスを、ゲームプレイ アビリティと動作させるために特化させたものです。
Unreal Engine でのゲームプレイ アビリティ タスク
この説明の通り、Gameplay Tasks と Ability Tasks は全く別のものというわけではなくて、Gameplay Tasks を Gameplay Ability 用に特化させたものが Ability Tasks です。
なので Ability Tasks を自作する際に継承する必要のある UAbilityTask というクラスは UGameplayTask を継承しています。
(↓参考:AbilityTask.h)
UCLASS(Abstract, MinimalAPI)
class UAbilityTask : public UGameplayTask
Gameplay Tasks は基本的にどのブループリントからでも使用することができましたが、Ability Tasks は Gameplay Ability 内でしか使用できません。
(たぶん)



タスクの定義方法
ここからは Gameplay Tasks と Ability Tasks の定義方法を解説します。
Gameplay Tasks
まずは Gameplay Tasks の定義方法についてです。
GameplayTask_WaitDelay.h と GameplayTask_WaitDelay.cpp を参考にして UGameplayTask_Sample というクラスを定義してみました。
InputValue という引数で受け取った文字列と「 World」という文字列を結合した文字列を3秒後に返すという内容です。
各行の意味や役割は以下のコードのコメントの通りです。
GameplayTask_Sample.h
#pragma once
#include "CoreMinimal.h"
#include "GameplayTask.h"
#include "GameplayTask_Sample.generated.h"
UCLASS()
class SAMPLE_API UGameplayTask_Sample : public UGameplayTask
{
GENERATED_BODY()
//デリゲートを宣言する(アウトプットピンの数と型、名前を設定する)
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FGameplayTaskSampleDelegate, FString, OutputValue);
public:
//コンストラクタ(メンバ変数の初期値を設定する)
UGameplayTask_Sample(const FObjectInitializer& ObjectInitializer);
//タスク完了時にブロードキャストするデリゲート
UPROPERTY(BlueprintAssignable)
FGameplayTaskSampleDelegate OnCompleted;
//ブループリントから呼び出す用の関数
UFUNCTION(BlueprintCallable, meta = (AdvancedDisplay = "TaskOwner, Priority", DefaultToSelf = "TaskOwner", BlueprintInternalUseOnly = "TRUE"))
static UGameplayTask_Sample* SampleGameplayTask(TScriptInterface<IGameplayTaskOwnerInterface> TaskOwner, const FString& InputValue, const uint8 Priority = 192);
// C++ から呼び出す用の関数
static UGameplayTask_Sample* SampleGameplayTask(IGameplayTaskOwnerInterface& InTaskOwner, const FString& InputValue, const uint8 Priority = FGameplayTasks::DefaultPriority);
protected:
//非同期処理を実装する関数
virtual void Activate() override;
private:
//タスク完了時の処理を実装する関数
void HandleOnCompleted();
//引数で受け取った値を保持する用のメンバ変数
FString CachedInputValue;
};
GameplayTask_Sample.cpp
#include "GameplayTask_Sample.h"
UGameplayTask_Sample::UGameplayTask_Sample(const FObjectInitializer& ObjectInitializer)
: Super(ObjectInitializer)
{
//メンバ変数の初期値を設定する
CachedInputValue = FString();
}
//タスクを作成して返す(ここに非同期処理を書くわけではない)
UGameplayTask_Sample* UGameplayTask_Sample::SampleGameplayTask(TScriptInterface<IGameplayTaskOwnerInterface> TaskOwner, const FString& InputValue, const uint8 Priority)
{
UGameplayTask_Sample* SampleGameplayTask = NewTaskUninitialized<UGameplayTask_Sample>();
if (SampleGameplayTask && TaskOwner.GetInterface())
{
SampleGameplayTask->InitTask(*TaskOwner, Priority);
SampleGameplayTask->CachedInputValue = InputValue;
}
return SampleGameplayTask;
}
//タスクを作成して返す(ここに非同期処理を書くわけではない)
UGameplayTask_Sample* UGameplayTask_Sample::SampleGameplayTask(IGameplayTaskOwnerInterface& InTaskOwner, const FString& InputValue, const uint8 Priority)
{
UGameplayTask_Sample* SampleGameplayTask = NewTaskUninitialized<UGameplayTask_Sample>();
if (SampleGameplayTask)
{
SampleGameplayTask->InitTask(InTaskOwner, Priority);
SampleGameplayTask->CachedInputValue = InputValue;
}
return SampleGameplayTask;
}
void UGameplayTask_Sample::Activate()
{
//3秒後に HandleOnCompleted() を呼び出す
FTimerHandle TimerHandle;
GetWorld()->GetTimerManager().SetTimer(TimerHandle, this, &UGameplayTask_Sample::HandleOnCompleted, 3.f);
}
void UGameplayTask_Sample::HandleOnCompleted()
{
//デリゲートをブロードキャストする
const FString OutputValue = CachedInputValue + TEXT(" World");
OnCompleted.Broadcast(OutputValue);
// EndTask() を呼び出してタスクを終了する
EndTask();
}
この SampleGameplayTask() をブループリントから呼び出すと、このような見た目になります。

Ability Tasks
次は Ability Tasks の定義方法についてです。
Ability Tasks の自作方法については AbilityTask.h で長文のコメントで説明されています。
そのコメントの原文と和訳は以下の通りです。
AbilityTask.h に書かれているコメント(原文)
AbilityTasks are small, self contained operations that can be performed while executing an ability. They are latent/asynchronous is nature. They will generally follow the pattern of ‘start something and wait until it is finished or interrupted’ We have code in K2Node_LatentAbilityCall to make using these in blueprints streamlined. The best way to become familiar with AbilityTasks is to look at existing tasks like UAbilityTask_WaitOverlap (very simple) and UAbilityTask_WaitTargetData (much more complex).
AbilityTask.h
These are the basic requirements for using an ability task:
1) Define dynamic multicast, BlueprintAssignable delegates in your AbilityTask. These are the OUTPUTs of your task. When these delegates fire, execution resumes in the calling blueprints.
2) Your inputs are defined by a static factory function which will instantiate an instance of your task. The parameters of this function define the INPUTs into your task. All the factory function should do is instantiate your task and possibly set starting parameters. It should NOT invoke any of the callback delegates!
3) Implement a Activate() function (defined here in base class). This function should actually start/execute your task logic. It is safe to invoke callback delegates here.
This is all you need for basic AbilityTasks.
CheckList:
-Override ::OnDestroy() and unregister any callbacks that the task registered. Call Super::EndTask too!
-Implemented an Activate function which truly ‘starts’ the task. Do not ‘start’ the task in your static factory function!
We have additional support for AbilityTasks that want to spawn actors. Though this could be accomplished in an Activate() function, it would not be possible to pass in dynamic “ExposeOnSpawn” actor properties. This is a powerful feature of blueprints, in order to support this, you need to implement a different step 3:
Instead of an Activate() function, you should implement a BeginSpawningActor() and FinishSpawningActor() function. BeginSpawningActor() must take in a TSubclassOf<YourActorClassToSpawn> parameters named ‘Class’. It must also have a out reference parameters of type YourActorClassToSpawn*& named SpawnedActor. This function is allowed to decide whether it wants to spawn the actor or not (useful if wishing to predicate actor spawning on network authority). BeginSpawningActor() can instantiate an actor with SpawnActorDeferred. This is important, otherwise the UCS will run before spawn parameters are set. BeginSpawningActor() should also set the SpawnedActor parameter to the actor it spawned. [Next, the generated byte code will set the expose on spawn parameters to whatever the user has set] If you spawned something, FinishSpawningActor() will be called and pass in the same actor that was just spawned. You MUST call ExecuteConstruction + PostActorConstruction on this actor! This is a lot of steps but in general, AbilityTask_SpawnActor() gives a clear, minimal example.
AbilityTask.h に書かれているコメント(ChatGPT による和訳)
AbilityTask は、アビリティの実行中に行われる 小さく、自己完結した処理単位です。本質的には Latent(遅延)/非同期処理であり、一般的に「何かを開始して、それが完了するか中断されるまで待つ」というパターンに従います。Blueprint での使用を簡単にするために、K2Node_LatentAbilityCall に関連コードが用意されています。AbilityTask に慣れる一番良い方法は、既存のタスクを見ることです。たとえば、UAbilityTask_WaitOverlap(とてもシンプル)や UAbilityTask_WaitTargetData(かなり複雑)などです。
ChatGPT による和訳
AbilityTask を使うための基本要件
1) AbilityTask 内に、dynamic multicast かつ BlueprintAssignable な delegate を定義します。これらはタスクの出力(OUTPUT) です。これらの delegate が発火すると、呼び出し元の Blueprint の実行が再開されます。
2) 入力は、static なファクトリ関数によって定義します。この関数はタスクのインスタンスを生成します。関数の引数が、そのまま タスクへの入力(INPUT) になります。ファクトリ関数の役割は「タスクを生成し、必要であれば初期パラメータを設定すること」だけです。callback delegate を呼び出してはいけません。
3) Activate() 関数(この基底クラスで定義されています)を実装します。この関数が、実際にタスクのロジックを開始・実行する場所です。ここで callback delegate を呼び出すのは安全です。
これだけで、基本的な AbilityTask は実装できます。
チェックリスト
-OnDestroy() をオーバーライドし、タスクが登録した callback を解除してください。その際、Super::EndTask も必ず呼び出してください。
-タスクを本当に「開始」するのは Activate() です。static ファクトリ関数内でタスクを開始してはいけません。
Actor をスポーンする AbilityTask には、特別なサポートがあります。Activate() 内でスポーンすることも可能ですが、その方法では動的な 「ExposeOnSpawn」プロパティを渡すことができません。ExposeOnSpawn は Blueprint の強力な機能なので、これをサポートするために手順 3 を別の形で実装する必要があります。Activate() の代わりに、BeginSpawningActor() と FinishSpawningActor() を実装する必要があります。BeginSpawningActor() には、Class という名前の TSubclassOf<YourActorClassToSpawn> 型の引数が必要です。また、SpawnedActor という名前の YourActorClassToSpawn*& 型の out 参照引数も必要です。この関数内で、Actor をスポーンするかどうかを判断して構いません(例:ネットワーク権限がある場合のみスポーンする、など)。Actor を生成する場合は、SpawnActorDeferred を使います。これは重要で、そうしないとスポーンパラメータが設定される前にUCS(User Construction Script)が実行されてしまいます。BeginSpawningActor() は、生成した Actor を SpawnedActor パラメータに必ず設定してください。(この後、生成されたバイトコードによって、ユーザーが設定した ExposeOnSpawn パラメータが自動的に設定されます)Actor を生成していた場合、次に FinishSpawningActor() が呼ばれ、先ほど生成した同じ Actor が渡されます。この関数内で、必ず ExecuteConstruction と PostActorConstruction を呼び出してください。手順は多いですが、全体像を理解するには AbilityTask_SpawnActor() が 最小かつ分かりやすい実装例になっています。
今回は AbilityTask_WaitDelay.h と AbilityTask_WaitDelay.cpp を参考にして UAbilityTask_Sample というクラスを定義してみました。
先ほどと同様に InputValue という引数で受け取った文字列と「 World」という文字列を結合した文字列を3秒後に返すという内容です。
各行の意味や役割は以下のコードのコメントの通りです。
AbilityTask_Sample.h
#pragma once
#include "CoreMinimal.h"
#include "Abilities/Tasks/AbilityTask.h"
#include "AbilityTask_Sample.generated.h"
UCLASS()
class SAMPLE_API UAbilityTask_Sample : public UAbilityTask
{
GENERATED_BODY()
//デリゲートを宣言する(アウトプットピンの数と型、名前を設定する)
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FAbilityTaskSampleDelegate, FString, ReturnValue);
public:
//コンストラクタ(メンバ変数の初期値を設定する)
UAbilityTask_Sample(const FObjectInitializer& ObjectInitializer);
//タスク完了時にブロードキャストするデリゲート
UPROPERTY(BlueprintAssignable)
FAbilityTaskSampleDelegate OnCompleted;
//ブループリントや C++ から呼び出す関数
UFUNCTION(BlueprintCallable, meta = (HidePin = "OwningAbility", DefaultToSelf = "OwningAbility", BlueprintInternalUseOnly = "TRUE"))
static UAbilityTask_Sample* SampleAbilityTask(UGameplayAbility* OwningAbility, const FString& InputValue);
protected:
//非同期処理を実装する関数
virtual void Activate() override;
private:
//タスク完了時の処理を実装する関数
void HandleOnCompleted();
//引数で受け取った値を保持する用のメンバ変数
FString CachedInputValue;
};
AbilityTask_Sample.cpp
#include "AbilityTask_Sample.h"
UAbilityTask_Sample::UAbilityTask_Sample(const FObjectInitializer& ObjectInitializer)
: Super(ObjectInitializer)
{
//メンバ変数の初期値を設定する
CachedInputValue = FString();
}
//タスクを作成して返す(ここに非同期処理を書くわけではない)
UAbilityTask_Sample* UAbilityTask_Sample::SampleAbilityTask(UGameplayAbility* OwningAbility, const FString& InputValue)
{
UAbilityTask_Sample* SampleAbilityTask = NewAbilityTask<UAbilityTask_Sample>(OwningAbility);
if (SampleAbilityTask)
{
SampleAbilityTask->CachedInputValue = InputValue;
}
return SampleAbilityTask;
}
void UAbilityTask_Sample::Activate()
{
//3秒後に HandleOnCompleted() を呼び出す
FTimerHandle TimerHandle;
GetWorld()->GetTimerManager().SetTimer(TimerHandle, this, &UAbilityTask_Sample::HandleOnCompleted, 3.f);
}
void UAbilityTask_Sample::HandleOnCompleted()
{
//デリゲートをブロードキャストするべきかどうか(アビリティが有効かどうか)を確認する
if (ShouldBroadcastAbilityTaskDelegates())
{
//デリゲートをブロードキャストする
const FString OutputValue = CachedInputValue + TEXT(" World");
OnCompleted.Broadcast(OutputValue);
}
// EndTask() を呼び出してタスクを終了する
EndTask();
}
この SampleAbilityTask() を Gameplay Ability Blueprint から呼び出すと、このような見た目になります。

Gameplay Tasks を定義したときとの違い
コンストラクタや Activate() の内容は UGameplayTask_Sample と全く同じですが、SampleAbilityTask() や HandleOnCompleted() の内容は少し異なります。
まず、SampleAbilityTask() で自身をインスタンス化する際、Gameplay Tasks のときは NewTaskUninitialized() でインスタンス化した後に手動で InitTask() していましたが、Ability Tasks では NewAbilityTask() でインスタンス化し、手動では InitTask() していません。
NewAbilityTask() の定義部分を見てみると以下のように書かれていました。
(↓参考:AbilityTask.h)
template <class T>
static T* NewAbilityTask(UGameplayAbility* ThisAbility, FName InstanceName = FName())
{
check(ThisAbility);
T* MyObj = NewObject<T>();
MyObj->InitTask(*ThisAbility, ThisAbility->GetGameplayTaskDefaultPriority());
UAbilityTask::DebugRecordAbilityTaskCreatedByAbility(ThisAbility);
MyObj->InstanceName = InstanceName;
return MyObj;
}
NewAbilityTask() ではそのクラスのインスタンス化と初期化(InitTask())、デバッグ情報の記録(DebugRecordAbilityTaskCreatedByAbility())、インスタンス名の設定などを行っていることがわかります。
(NewTaskUninitialized() は単にそのクラスを NewObject() して返しているだけなので NewObject() と同義です。)
HandleOnCompleted() ではデリゲートをブロードキャストする前に ShouldBroadcastAbilityTaskDelegates() の戻り値を確認しています。
ShouldBroadcastAbilityTaskDelegates() の宣言部分には以下のコメントが書かれていて、これを和訳すると「これはデリゲートをアビリティグラフに再度送信する前に呼び出す必要があります。これにより、アビリティがまだ有効であることが保証されます。」となります。
This should be called prior to broadcasting delegates back into the ability graph. This makes sure the ability is still active.
AbilityTask.h
Ability Tasks ではデリゲートをブロードキャストする前に ShouldBroadcastAbilityTaskDelegates() でそのアビリティがまだ有効な状態かどうかを確認する必要があるようです。
タスクの使用方法
ここからは Gameplay Tasks と Ability Tasks の使用方法について解説します。
タスクの実行
まずはタスクの実行方法についてです。
ブループリントでの実行方法は単にそのノードを呼び出すだけなので、ここでは C++ での実行方法について解説します。
Gameplay Tasks
先ほど定義した UGameplayTask_Sample::SampleGameplayTask() をアクタクラスの BeginPlay() で実行してみます。
今回は UGameplayTasksComponent を SampleGameplayTask() に渡します。
各行の意味や役割は以下のコードのコメントの通りです。
SampleActor.h
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "SampleActor.generated.h"
UCLASS()
class SAMPLE_API ASampleActor : public AActor
{
GENERATED_BODY()
public:
ASampleActor();
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly)
TObjectPtr<UGameplayTasksComponent> GameplayTasksComponent;
protected:
virtual void BeginPlay() override;
public:
virtual void Tick(float DeltaTime) override;
private:
//コールバック関数(UFUNCTION() を必ず付ける)
UFUNCTION()
void OnCompleted(const FString OutputValue);
};
SampleActor.cpp
#include "SampleActor.h"
#include "GameplayTasksComponent.h"
#include "GameplayTask_Sample.h" //追加
ASampleActor::ASampleActor()
{
PrimaryActorTick.bCanEverTick = true;
GameplayTasksComponent = CreateDefaultSubobject<UGameplayTasksComponent>(TEXT("GameplayTasksComponent"));
}
void ASampleActor::BeginPlay()
{
Super::BeginPlay();
// C++ 用の関数を使って UGameplayTask_Sample* を取得する
//(IGameplayTaskOwnerInterface を参照渡しする)
UGameplayTask_Sample* SampleGameplayTask = UGameplayTask_Sample::SampleGameplayTask(*GameplayTasksComponent, TEXT("Hello"));
if (SampleGameplayTask)
{
//コールバック関数を登録する
SampleGameplayTask->OnCompleted.AddDynamic(this, &ASampleActor::OnCompleted);
// ReadyForActivation() でタスクを実行する
SampleGameplayTask->ReadyForActivation();
}
}
void ASampleActor::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
}
//コールバック関数
void ASampleActor::OnCompleted(const FString OutputValue)
{
UE_LOG(LogTemp, Log, TEXT("%s"), *OutputValue);
}
Ability Tasks
次は先ほど定義した UAbilityTask_Sample::SampleAbilityTask() を Gameplay Ability の ActivateAbility() で実行してみます。
各行の意味や役割は以下のコードのコメントの通りです。
(Gameplay Tasks を実行したときとほとんど同じです。)
SampleGameplayAbility.h
#pragma once
#include "CoreMinimal.h"
#include "Abilities/GameplayAbility.h"
#include "SampleGameplayAbility.generated.h"
UCLASS()
class SAMPLE_API USampleGameplayAbility : public UGameplayAbility
{
GENERATED_BODY()
protected:
virtual void ActivateAbility(const FGameplayAbilitySpecHandle Handle, const FGameplayAbilityActorInfo* ActorInfo, const FGameplayAbilityActivationInfo ActivationInfo, const FGameplayEventData* TriggerEventData) override;
private:
//コールバック関数(UFUNCTION() を必ず付ける)
UFUNCTION()
void OnCompleted(const FString OutputValue);
};
SampleGameplayAbility.cpp
#include "SampleGameplayAbility.h"
#include "AbilityTask_Sample.h" //追加
void USampleGameplayAbility::ActivateAbility(const FGameplayAbilitySpecHandle Handle, const FGameplayAbilityActorInfo* ActorInfo, const FGameplayAbilityActivationInfo ActivationInfo, const FGameplayEventData* TriggerEventData)
{
Super::ActivateAbility(Handle, ActorInfo, ActivationInfo, TriggerEventData);
//自身を第一引数に渡して UAbilityTask_Sample* を取得する
UAbilityTask_Sample* SampleAbilityTask = UAbilityTask_Sample::SampleAbilityTask(this, TEXT("Hello"));
if (SampleAbilityTask)
{
//コールバック関数を登録する
SampleAbilityTask->OnCompleted.AddDynamic(this, &USampleGameplayAbility::OnCompleted);
// ReadyForActivation() でタスクを実行する
SampleAbilityTask->ReadyForActivation();
}
}
//コールバック関数
void USampleGameplayAbility::OnCompleted(const FString OutputValue)
{
UE_LOG(LogTemp, Log, TEXT("%s"), *OutputValue);
}
タスクの終了
また、UGameplayTask には EndTask() という public かつ BlueprintCallable な関数が定義されているので、以下のようにしてブループリントや C++ からそれを呼び出すと、そのタスクを手動で終了させることもできます。

SampleGameplayTask->EndTask();
SampleAbilityTask->EndTask();


