UnrealEngine4  リフレクション(C++とBluePrint連携)まわりの調査

TD;DR
UnrealEngineを初めて触る機会があったので、まずはリフレクションまわりを調査


#概要
UnrealEngineでは、主にプログラマが作業するC++と
デザイナや企画なども触りやすいビジュアル言語 BluePrint　が存在する
Unreal独自の リフレクション機能により、双方で関数や変数、構造体、列挙体をやり取りする仕組みがある

基本的に、C++でベースクラスを作成し、BluePrintはそれを継承し、変数や関数にアクセスをする
C++からBluePrintにアクセスするには、イベントという仕組みを使い
C++では実態のないメソッドを作り呼び出す事ができる

ただし、BluePrintではメモリ管理が自動で行われるため、リフレクションを使うC++部分は ガーベージコレクション等を行う必要がある

それらの仕組みを Unrealは提供している


#C++クラスを作成しBluePrintで継承する

https://docs.unrealengine.com/latest/JPN/Programming/QuickStart/2/index.html

上記のようにC++でクラスを作成する。
Actorというのが、Unrealの色々な機能を使うことができる基底クラス

それを親に、BluePrintクラスを作成

##C++コード

```cpp

#pragma once

#include "GameFramework/Actor.h"
#include "MyActor.generated.h"

UCLASS()
class HOGE_API AMyActor : public AActor
{
	GENERATED_BODY()
	
public:	
	// Sets default values for this actor's properties
	AMyActor();

	// Called when the game starts or when spawned
	virtual void BeginPlay() override;
	
	// Called every frame
	virtual void Tick( float DeltaSeconds ) override;

};
```

上記が自動生成されたコード。

AActorクラスを継承している。 Unrealではクラス名の頭に意味があり
Uがつくものは UObject、AはActorを継承している
構造体やUnreal文字列等のリフレクションに渡せる汎用クラスはFで始まり
EnumはEで始まり、コンテナはTではじまる

ここで疑問が何個かあるとおもう


## #include "MyActor.generated.h"

自動生成されたヘッダファイル。
ヘッダを変更するとUnrealBuildToolが自動的に生成する　リフレクション用のファイル
後々中身を覗くと リフレクションが行われているのがわかると思う


## UCLASS()

コードを追うと

```cpp

#if UE_BUILD_DOCS
#define UCLASS(...)
#else
#define UCLASS(...) BODY_MACRO_COMBINE(CURRENT_FILE_ID,_,__LINE__,_PROLOG)
#endif

#define BODY_MACRO_COMBINE_INNER(A,B,C,D) A##B##C##D
#define BODY_MACRO_COMBINE(A,B,C,D) BODY_MACRO_COMBINE_INNER(A,B,C,D)

```

とりあえず　あまり気にせず、Unrealに管理させるクラスには UCLASS() が必要と。


## HOGE_API

HOGEはプロジェクト名
これも気にしない


## : public AActor
Actorから継承させなければ、Unrealの色々な機能が使えない。
UObject、AActor、ACharacter・・等色々あるが今回は AActorで行う


## GENERATED_BODY()
 
```cpp
#define GENERATED_BODY(...) BODY_MACRO_COMBINE(CURRENT_FILE_ID,_,__LINE__,_GENERATED_BODY)
#define BODY_MACRO_COMBINE_INNER(A,B,C,D) A##B##C##D
#define BODY_MACRO_COMBINE(A,B,C,D) BODY_MACRO_COMBINE_INNER(A,B,C,D)
```
これも特に気にせず、Unrealに管理させる場合に必要とおぼえておこう


# 構造体、enum、メンバ変数

プロジェクトは BluePrintのThirdPersonExanmple
プロジェクト名：BPTest
C++クラス： MyActor
派生したBluePrintクラス：BP_MyActor



## 構造体

構造体をBluePrintと両方で使いたい場合は、基底クラスのC++側で リフレクション付けて定義します

### コード


```cpp:MyActor.h
USTRUCT(BlueprintType)
struct BPSAMPLE_API FHogeStruct {
	GENERATED_USTRUCT_BODY()

public:
	UPROPERTY()	float x;
	UPROPERTY(BlueprintReadOnly)	float y;
	UPROPERTY(BlueprintReadWrite)	float z;
};

```

### 名前
今回の構造体名は FHogeStruct
構造体は頭に Fのプリフィックスを付けねば認識してくれないのは Unrealの仕様


### USTRUCT()
BluePrintに公開するときに必要
ただし、これだけではガーベージコレクションに入らないので、メンバ1つずつに対して UPROPERTY設定必要

パラメータは下記
https://docs.unrealengine.com/latest/INT/Programming/UnrealArchitecture/Reference/Structs/Specifiers/index.html



### UPROPERTY()
メンバそれぞれに対して、BluePrintにリフレクションするパラメータを設定する
今回は3種類書いてみた
パラメーター無し、BlueprintReadOnly、BlueprintReadWrite
結果から言うと
パラメータ無しだと Blueprintに公開されない
BlueprintReadOnlyだと 書き込み不能
BlueprintReadWrite　だと読み書き可能
みた通りの挙動


パラメータ詳細は下記
https://docs.unrealengine.com/latest/INT/Programming/UnrealArchitecture/Reference/Properties/Specifiers/index.html


### BluePrintでの結果

BP_MyActorのブループリントを開き、HogeStructのノードを開く

![SnapCrab_BP_MyActor_2016-9-7_18-3-49_No-00.png](https://qiita-image-store.s3.amazonaws.com/0/13916/1e5d8b50-f7e0-2d2f-44db-60fd49731965.png)




見て分かる通り、IN (書き込み)は Zのみ、OUT（読み込み）はYとZで、Xは読み書きどちらも不能

これで　構造体をBluePrintとC++で使えるようになった


## Enum

EnumをBluePrintと両方で使いたい場合は、基底クラスのC++側で リフレクション付けて定義します

### コード

Class宣言の前に

```cpp:MyActor.h
UENUM(BlueprintType)
enum class EHogeEnum : uint8 {
	HOGE,
	HOGE2,
	HOGE3
};
```

### 名前
今回の構造体名は EHogeEnum
Enumは頭に Eのプリフィックスを付けねば認識してくれないのは Unrealの仕様
また、内部表現は8ビット固定


### UENUM()
BluePrintに公開するときに必要


### BluePrintでの結果

BP_MyActorのブループリントを開き、HogeEnumのノードを開く


![SnapCrab_BP_MyActor_2016-9-7_18-19-8_No-00.png](https://qiita-image-store.s3.amazonaws.com/0/13916/7e6e9137-2a86-b74f-d908-fc54ed7582f9.png)


これで　EnumをBluePrintとC++で使えるようになった




## メンバ変数


メンバ変数をBluePrintに公開するには、基底クラスのC++側で リフレクション付けて定義します

### コード

Class

```cpp:MyActor.h
UCLASS(Blueprintable)
class BPSAMPLE_API AMyActor : public AActor
{
	GENERATED_BODY()
	
private:
	// UPROPERTY(BlueprintReadWrite, Category = "MyTest")	float private_;    // privateではアクセスを書くとコンパイルエラー
	UPROPERTY()	float private_;

protected:
	UPROPERTY(BlueprintReadOnly, Category = "MyTest")	float protected_;


public:	
	UPROPERTY(BlueprintReadWrite, Category = "MyTest")	float public_;

	// Sets default values for this actor's properties
	AMyActor();

	// Called when the game starts or when spawned
	virtual void BeginPlay() override;
	
	// Called every frame
	virtual void Tick( float DeltaSeconds ) override;

};

```


### UPROPERTY()
構造体の時と同じく、BlueprintReadOnly、BlueprintReadWrite  を選べる
また、Categoryをつけると、BluePrintでノードを検索するときに カテゴリー名で検索できるので便利
Privateの場合は BluePrintから呼び出せないため、それらのパラメータを付けることは不可能


パラメータ詳細は下記

https://docs.unrealengine.com/latest/INT/Programming/UnrealArchitecture/Reference/Properties/Specifiers/index.html


### BluePrintでの結果

private_  変数はアクセス不能
protected_ 変数はアクセス可能
public_ 変数はアクセス可能

![SnapCrab_BP_MyActor_2016-9-7_18-32-49_No-00.png](https://qiita-image-store.s3.amazonaws.com/0/13916/4324ab0e-be3a-de2f-9a21-d0c1de2445c9.png)



#メソッド


*パラメータ一覧
下記をみるとよい
今回調査するのは
パラメータなし、BluePrintCallable、BlueprintImplementableEvent
のみ

https://docs.unrealengine.com/latest/JPN/Programming/UnrealArchitecture/Reference/Functions/index.html




### パラメータ無し


```cpp:MyActor.h
	UFUNCTION(Category = "MyFunc")
		virtual void FuncNone() {};
	UFUNCTION(Category = "MyFunc")
		virtual void FuncNone2(int n) {};
	UFUNCTION(Category = "MyFunc")
		virtual int FuncNone3(int n) { return 1; };


```

パラメータを付けない場合は、BluePrintと繋がることはない
だが、後に出てくる レプリケーション等のUnrealEngineで使う関数には指定する必要がある
![SnapCrab_BP_MyActor_2016-9-7_20-11-32_No-00.png](https://qiita-image-store.s3.amazonaws.com/0/13916/30eba247-3187-4c66-fe92-aff6039f0314.png)






### BluePrintCallable


```cpp:MyActor.h
	UFUNCTION(BluePrintCallable, Category="MyFunc")
		virtual void FuncCallable() {};
	UFUNCTION(BluePrintCallable, Category = "MyFunc")
		virtual void FuncCallable2(int n) {};
	UFUNCTION(BluePrintCallable, Category = "MyFunc")
		virtual int FuncCallable3(int n) { return 1; };

```

BluePrintからC++のコードを実行する際に使う、最も多い使い方
基本的にUnrealではC++のクラスを継承しBluePrintを作る
BluePrintで関数を Override可能




### BlueprintImplementableEvent


```cpp:MyActor.h
	UFUNCTION(BlueprintImplementableEvent, Category = "MyFunc")
		void FuncImplementableEvent() ;
	UFUNCTION(BlueprintImplementableEvent, Category = "MyFunc")
		void FuncImplementableEvent2(int n);
	UFUNCTION(BlueprintImplementableEvent, Category = "MyFunc")
		int FuncImplementableEvent3(int n);


```

C++からBluePrintの関数を呼ぶための仕組み
名前から推測するに イベントのような形で実行するのだろう
実際にBluePrintでもイベントとして表示される

virtual不可能＆C++側で関数をImplement不可能
関数定義だけ用意し、C++からこのコードを呼べば、BluePrintで定義した関数が呼べる
イベントなので　引数は取れるが戻り値は返せない
コンパイルエラーにはならないが、戻り値をつけるとBluePrintから見えなくなる



### BlueprintPure


```cpp:MyActor.h
//	UFUNCTION(BlueprintPure, Category = "MyFunc")
//		virtual void FuncPure(){};
//	UFUNCTION(BlueprintPure, Category = "MyFunc")
//		void FuncPure2(int n) {};
	UFUNCTION(BlueprintPure, Category = "MyFunc")
		virtual int FuncPure3(int n) { return 1; };
```

ヘルプによると　所有するオブジェクトに影響を与えることなく・・・
らしく、戻り値がなければダメのようだ





##結果
![SnapCrab_BP_MyActor_2016-9-7_20-11-32_No-00.png](https://qiita-image-store.s3.amazonaws.com/0/13916/bd25fb70-39c9-9c16-770d-b494e462b63b.png)



パラメータ無しはBluePrintに表示されない
ImplementableEventは イベントとして表示。ただし戻り値を設定すると表示されない
Callableは実行品が両端についた通常の関数
Pureは実行ピンのない、値をかえすだけのもの


#ついでに、リフレクションに指定できる型

全ての型がリフレクションで使えるわけではない
基本的には Unrealで管理されたもの（UObjectを継承し、ガーベージコレクション等に対応したもの）しか送れない
一部のプリミティブ型は送れる




```cpp:hoge.h
UENUM(BlueprintType)
enum class EHogeEnum : uint8 {
	HOGE,
	HOGE2,
	HOGE3
};

USTRUCT(BlueprintType)
struct BPSAMPLE_API FHoge {
	GENERATED_USTRUCT_BODY()
		float x;
};

USTRUCT(BlueprintType)
struct BPSAMPLE_API FHogeStruct {
	GENERATED_USTRUCT_BODY()

public:
	UPROPERTY(BlueprintReadWrite)	FHoge hoge_;
	UPROPERTY(BlueprintReadWrite)	EHogeEnum enum_;

	UPROPERTY(BlueprintReadWrite)	uint8	uint8_;
//	UPROPERTY(BlueprintReadWrite)	uint16	uint16_;
//	UPROPERTY(BlueprintReadWrite)	uint32	uint32_;
//	UPROPERTY(BlueprintReadWrite)	uint64	uint64_;
//	UPROPERTY(BlueprintReadWrite)	int8	int8_;
//	UPROPERTY(BlueprintReadWrite)	int16	int16_;
	UPROPERTY(BlueprintReadWrite)	int32	int32_;
//	UPROPERTY(BlueprintReadWrite)	int64	int64_;

	UPROPERTY(BlueprintReadWrite)	float	float_;
//	UPROPERTY(BlueprintReadWrite)	double	double_;

	UPROPERTY(BlueprintReadWrite)	bool	bool_;

	UPROPERTY(BlueprintReadWrite)	FString	FString_;
	UPROPERTY(BlueprintReadWrite)	FName	FName_;
	UPROPERTY(BlueprintReadWrite)	AActor	*AActor_;

	UPROPERTY(BlueprintReadWrite)	TArray<int32>	TArray_;
//	UPROPERTY(BlueprintReadWrite)	TMap<int32, int32>	TMap_;
//	UPROPERTY(BlueprintReadWrite)	TSet<int32>	TSet_;

};
```

コメントになっているのは、渡せないもの。


構造体、Enumは USTRUCT,UENUM 付きのものは渡せる
プリミティブ型では
uint8、int32、float、bool  のみ

コンテナは TArrayのみ

UObjectを継承しているクラスポインタは渡せる

![SnapCrab_BP_MyActor_2016-9-7_22-14-16_No-00.png](https://qiita-image-store.s3.amazonaws.com/0/13916/5dfb5db8-3038-09df-b32c-f9c94de45353.png)