執筆バージョン: Unreal Engine 4.20
Latentノードといえばよく見かける以下のような
ノードの右上に時計のマークが表示されてるノードのことを言います。
ノード内部で処理が終わり次第、次に進むことができるものです。
これをプロジェクト専用に追加する場合FPendingLatentActionを継承したりFLatentActionInfoを使用して実装することができるのですが(※1 )
少しめんど……く……さい……
なんてことを思ってたんですが実はもっとシンプルに作ることができる方法があったので今回はそれをご紹介したいと思います。
では早速サンプルをご確認ください。
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "MyAsyncFunction.h"
#include "Engine/World.h"
#include "TimerManager.h"
UMyAsyncFunction::UMyAsyncFunction(const FObjectInitializer& ObjectInitializer)
:Super(ObjectInitializer)
{
}
UMyAsyncFunction* UMyAsyncFunction::MyAsyncFunction(UObject* WorldContextObject)
{
/** 自身を生成しGameInstanceに登録して勝手にGCされないようにする */
UMyAsyncFunction* Action = NewObject<UMyAsyncFunction>();
Action->RegisterWithGameInstance(WorldContextObject);
return Action;
}
void UMyAsyncFunction::Activate()
{
/** ノードが実行されたので処理を開始
サンプルではとりあえず1秒で終了 */
FTimerManager& TimeManager = GWorld->GetTimerManager();
TimeManager.SetTimer(TimerHandle,this,&UMyAsyncFunction::OnTimer,1.0f,false);
}
void UMyAsyncFunction::OnTimer()
{
/** ノードを終了したことを通知する */
Completed.Broadcast(FMath::RandRange(0,10));
//Completed2.Broadcast(FMath::RandRange(0,10));
//Completed3.Broadcast(FMath::RandRange(0,10));
//Completed4.Broadcast(FMath::RandRange(0,10));
/** 終わったので登録を解除しGC対象に */
SetReadyToDestroy();
}
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#pragma once
#include "CoreMinimal.h"
#include "Kismet/BlueprintAsyncActionBase.h"
#include "MyAsyncFunction.generated.h"
/**
* ノード終了時に呼ぶデリゲート
*/
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FAsyncCompletedMyFunction,int32,Result);
/**
* ノード終了時に呼ぶデリゲートその2
*/
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FAsyncCompletedMyFunctionFloat,float,ResultFloat);
/**
*
*/
UCLASS()
class MYPROJECT_API UMyAsyncFunction : public UBlueprintAsyncActionBase
{
GENERATED_BODY()
public:
/** ノードでの処理終了時に呼ぶデリゲート */
UPROPERTY(BlueprintAssignable)
FAsyncCompletedMyFunction Completed;
UPROPERTY(BlueprintAssignable)
FAsyncCompletedMyFunction Completed2;
//UPROPERTY(BlueprintAssignable)
//FAsyncCompletedMyFunctionFloat Completed3;
//UPROPERTY(BlueprintAssignable)
//FAsyncCompletedMyFunction Completed4;
private:
FTimerHandle TimerHandle;
public:
UMyAsyncFunction(const FObjectInitializer& ObjectInitializer);
/**
* Latentノード(BlueprintInternalUseOnlyを指定する)
* @param WorldContextObject ワールドのコンテキストオブジェクトこれからGameinstanceに自分を登録する
* @return 生成されたUMyAsyncFunction
* @memo Engine\Source\Editor\Kismet\Private\Nodes\K2Node_AsyncAction.cpp参照
*/
UFUNCTION(BlueprintCallable,Category = "AsyncTest",meta = ( WorldContext = "WorldContextObject",BlueprintInternalUseOnly = "true" ))
static UMyAsyncFunction* MyAsyncFunction(UObject* WorldContextObject);
/** Begin UBlueprintAsyncActionBase */
/**
* ノード実行時に呼ばれる関数
*/
virtual void Activate() override;
/** End UBlueprintAsyncActionBase */
void OnTimer();
};
上記のサンプルコードではUBlueprintAsyncActionBaseというクラスを継承して作成したものですがこれだけで
という感じにLatentノードを作成することができます。またコード上の変数「Completed2」のコメントを消すだけで
のようにピンを増やすこともできます。
UBlueprintAsyncActionBaseを使用してLatentノードを作成する場合のポイントは4点です。
UBlueprintAsyncActionBaseを継承したクラスを生成し返すStaticな関数を定義し、メタ情報にBlueprintInternalUseOnly = “true”を指定する
ノード終了時に通知するためのデリゲートを定義する
Activateをオーバーライドして処理を実装する
不要になったらSetReadyToDestroyを呼び出してGC対象に
短いですが今回は以上になります。少しでも皆様の開発に役立てばと思います。
ここまで読んでいただきありがとうございました。
※1
FLatentActionInfo、FPendingLatentActionを使用しての実装に関しては以下のブログが参考になるかと思います。
http://unwitherer.blogspot.com/2017/06/unrealclatent_11.html
http://unwitherer.blogspot.com/2017/06/unrealclatent.html