Let's Enjoy Unreal Engine

Unreal Engineを使って遊んでみましょう

UE4 Unreal C++のリフレクションを使って文字列で関数を呼び出す方法について

今回の記事もC++なので、完全にプログラマー向けとなります。

UE4で利用できるUnreal C++はとても強力な機能を持っていますが、本来のC++にはない独自のリフレクション機能を使うともっと面白いことができます。

普段ブループリントを使っている人にはさほどありがたい話ではないかもしれませんが、C++では通常このような関数呼び出しはできませんので、とても重宝します。
まずは適当なC++プロジェクトを用意して、C++クラスでアクターを作成します。

少し古い情報となってしまっていますが、C++クラスの作り方などは過去にも記事にしたことがあるので参考にしてください。
UE4 C++コードをブループリントで使えるようにする(関数ライブラリー編) - Let's Enjoy Unreal Engine
UE4 C++コードをブループリントで使えるようにする(アクタークラス編) - Let's Enjoy Unreal Engine

アクターに関数などの宣言と定義を追加する

適当なC++クラスのアクターをプロジェクトに追加したら、そのファイルのヘッダーを開きます。
ヘッダーに以下のような宣言を追加します。

UCLASS()
class CPPTEST_API AMyActor : public AActor
{
	GENERATED_BODY()
	
public:	
	AMyActor();

	virtual void BeginPlay() override;
	
	virtual void Tick( float DeltaSeconds ) override;

	// 追加した関数。この関数でリフレクション呼び出しをする
	UFUNCTION(BlueprintCallable, Category = Reflection)
	void ExecuteFunction(FString FuncName, int32 a, float b);

	// 実際にリフレクションで呼び出される関数
	UFUNCTION()
	void Func(int32 a, float b, FString s);
};


これでヘッダー側はOKです。次はソース側です。

AMyActor::AMyActor()
{
	PrimaryActorTick.bCanEverTick = false;
}

void AMyActor::BeginPlay()
{
	Super::BeginPlay();

	// BeginPlay時に呼び出し
	ExecuteFunction(TEXT("Func"), 10, 0.123f);
}

void AMyActor::Tick( float DeltaTime )
{
	Super::Tick( DeltaTime );
}

void AMyActor::ExecuteFunction(FString FuncName, int32 a, float b)
{
	// 関数呼び出しコマンドの文字列を作成する
	const FString FuncCommand = FString::Printf(TEXT("%s %d %f %s"), *FuncName, a, b, *GetName());
	FOutputDeviceNull Ar;

	// Func関数を呼び出す
	CallFunctionByNameWithArguments(*FuncCommand, Ar, this, true);
}

void AMyActor::Func(int32 a, float b, FString s)
{
	// PrintStringと同じようにオンスクリーンでテキストを表示する
	GEngine->AddOnScreenDebugMessage(-1, 10.f, FColor::Red, FString::Printf(TEXT("CallFunc!! %d %f %s"), a, b, *s));
}

これでC++側の実装は完了です。
あとはエディターに戻ってアクターの配置を行います。
ドラック&ドロップでレベル上にアクターを配置してください。

f:id:alwei:20160628214824p:plain

関数の呼び出し確認をする

実際にプレイを行い、オンスクリーン上にテキストが出ている事を確認します。

f:id:alwei:20160628215014p:plain

問題なさそうです。引数もちゃんと取得できており、アクター名の表示もできています。

では今度はこれをブループリントから呼び出してみます。C++クラスのアクターを継承したブループリントを作成してみてください。あとはそれをC++アクターの時と同じようにレベル上に配置しておきます。
ブループリント上で呼び出せるようにしておいた、"Execute Function"ノードを配置し、BeginPlayと接続します。引数も必要なものを入力しておきます。

f:id:alwei:20160628215337p:plain

あとは再度実行してみます。

f:id:alwei:20160628215747p:plain

C++側とブループリント側のEvent BeginPlayが1度ずつ呼び出されています。これはブループリント側ではBeginPlayは仮想関数としてみなされていないので、両方が呼ばれることになります。
ブループリント用の仮想関数が必要であれば別途用意する必要がありますが、ここではこれを解説しません。

これで無事、目的を達成することができました。

リフレクション呼び出しのまとめ

UE4のリフレクション機能を使って、文字列だけで関数呼び出しができました。引数も文字列になりますが、FString::Printf()は静的型安全な実装になっているので、通常のprintfのような危険性はありません。

リフレクション呼び出しを上手く利用することによって、C++では本来不可能な幅広い利用方法が可能となります。

ただし、リフレクションによる呼び出しは通常の関数呼び出しに比べても安いコストではありません。毎フレーム呼ぶようなTickなどで使用するのは止めましょう。