【UE】C++ を用いた Latent(非同期)ノードの作り方

Unreal Engine

手順

スクリプトの作成

手順1

エディタ上部の「ToolsNew C++ Class…」を押す。

手順2

All Classes」タブに切り替え、BlueprintAsyncActionBase を選択して右下の「Next>」を押す。

手順3

スクリプトのファイル名とパスを決め、右下の「Create Class」を押す。

「Runtime/Engine/Classes/GameFramework/AsyncActionHandleSaveGame.h」や「Runtime/Engine/Private/AsyncActionLoadPrimaryAsset.h」等のエンジン側のコードを見ると、Latent ノード用のクラスのファイル名は「AsyncAction{動詞}{名詞}」が多い。

コーディング

手順4

DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam({デリゲート名}, {戻り値の型名}, {戻り値名});」(戻り値が1つのみの場合)と「UPROPERTY(BlueprintAssignable) {デリゲート名} {変数名};」と記述してデリゲートを宣言する。

デリゲートに関してはドクロモエさんの「【UE4 C++】デリゲートの使い方まとめ」という記事が非常に参考になるので、そちらの記事を参考にしてデリゲートを宣言すると良い。
#pragma once

#include "CoreMinimal.h"
#include "Kismet/BlueprintAsyncActionBase.h"
#include "AsyncActionDoSomething.generated.h"

DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnCompletedSomething, FString&, OutputValue);

UCLASS()
class SAMPLE_API UAsyncActionDoSomething : public UBlueprintAsyncActionBase
{
	GENERATED_BODY()

public:
	UPROPERTY(BlueprintAssignable)
	FOnCompletedSomething Completed;
};

手順5

UFUNCTION(BlueprintCallable, meta = (BlueprintInternalUseOnly = “true”, WorldContext = “WorldContextObject”)) static {作成したクラス名}* {関数名}(UObject* WorldContextObject, {引数の型名} {引数名});」等と記述して関数を宣言し、引数を保持するようのメンバ変数も宣言する。

Latent(非同期)ノードの名前は「Async{動詞}{名詞}」が一般的。

BlueprintInternalUseOnly
このmeta情報がある関数は他の関数やノードの内部実装として使われる関数を意味します。ブループリント上から呼び出せないようになります。

[UE4] meta情報を活用しエディタでの動作を制御しよう!

WorldContextObject は GetWorld()が実装されたUObject、つまり World への参照アクセスを持ったオブジェクトのことです。

WorldContextObject についての理解
#pragma once

#include "CoreMinimal.h"
#include "Kismet/BlueprintAsyncActionBase.h"
#include "AsyncActionDoSomething.generated.h"

DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnCompletedSomething, const FString&, OutputValue);

UCLASS()
class SAMPLE_API UAsyncActionDoSomething : public UBlueprintAsyncActionBase
{
	GENERATED_BODY()

public:
	UPROPERTY(BlueprintAssignable)
	FOnCompletedSomething Completed;

	UFUNCTION(BlueprintCallable, meta = (BlueprintInternalUseOnly = "true", WorldContext = "WorldContextObject"))
	static UAsyncActionDoSomething* AsyncDoSomething(UObject* WorldContextObject, const FString& InputValue);

private:
	FString InputValue;//受け取った引数を保持しておくようのメンバ変数
};

手順6

宣言した関数の定義をソースファイルに下記のように記述する。

  1. クラスのインスタンスを作成する
  2. 受け取った引数を、作成したクラスのメンバ変数に代入する
  3. 作成したクラスのインスタンスをゲームインスタンスに登録してガベージコレクションの影響を受けないようにする
  4. 作成したクラスのインスタンスを返す
UAsyncActionDoSomething* UAsyncActionDoSomething::AsyncDoSomething(UObject* WorldContextObject, const FString& InputValue)
{
	UAsyncActionDoSomething* Action = NewObject<UAsyncActionDoSomething>();

        //受け取った引数をメンバ変数に保持する
	Action->InputValue = InputValue;

	//ガベージコレクションでこのクラスのインスタンスが勝手に消されないようにする
	Action->RegisterWithGameInstance(WorldContextObject);

	return Action;
}

手順7

「OnCompleted()」等の名前の関数をヘッダーファイルで宣言し、その関数の定義をソースファイルにて下記のように記述する。
(必要に応じて引数も設定する)

void UAsyncActionDoSomething::OnCompleted(const FString& OutputValue)
{
	//デリゲートを呼び出す
	Completed.Broadcast(OutputValue);

	//ガベージコレクションの対象に戻す
	SetReadyToDestroy();
}

手順8

ヘッダーファイルで「public: void Activate() override;」と記述してソースファイルにて親クラスの「Activate()」を上書きする。

void UAsyncActionDoSomething::Activate()
{
        //ラムダ式などを用いて非同期で「OnCompleted()」を呼び出す処理
}

デバッグ

手順9

ブループリントのグラフで C++ 関数を呼び出して正常に動作する事を確認する。

その他

参考記事

お問い合わせ

    タイトルとURLをコピーしました