March 27, 2014

アンリアルのプロパティ システム (リフレクション)

作成 Michael Noland

リフレクションは、プログラムが実行時にプログラム自身を検査する機能です。これはとてつもなく便利な機能であり、アンリアル・エンジン の基礎的なテクノロジーとして、エディタ内の詳細パネルや、シリアライゼーション、ガーベジコレクション、ネットワークのレプリケーション、ブループリント/C++ の通信といった多くのシステムを支えています。ただし、C++ は本来リフレクションがサポートされていません。そのため Unreal には、C++ のクラスや構造体、関数、メンバー変数、列挙体に関する情報を取り込み、問い合わせ、操作するための独自のシステムが備わりました。通常私たちはリフレクションのことをプロパティ システムとみなします。リフレクションはグラフィックスの用語でもあるのですから。

このリフレクション システムは、選択式です。ユーザーは、リフレクション システムから見えるようにする型やプロパティにアノテーションを付ける必要があります。そうすることによって、プロジェクトをコンパイルする際に、Unreal Header Tool (UHT) がその情報が取り込めるようになります。

マークアップ

ヘッダにリフレクションされている型が含まれていることを示すマークを付けるために、特別な include をファイルの先頭に置きます。これによって、UHT は、このファイルを評価の対象にすることができます。また、これはシステムの実装のためにも必要です (詳しくは「舞台裏をのぞく」のセクションをご覧ください)。

#include "FileName.generated.h"

これで、UENUM()、UCLASS()、USTRUCT()、UFUNCTION()、UPROPERTY() を使って、ヘッダの中でさまざまな型やメンバー変数にアノテーションを付けることができるようになります。これらのマクロはそれぞれ、型またはメンバーの宣言よりも先に置かれ、付加的な指定子キーワードを含むことができます。実際のワールドのサンプルを見てみましょう (StrategyGame からのものです)。

//////////////////////////////////////////////////////////////////////////

// Base class for mobile units (soldiers)

#include "StrategyTypes.h"

#include "StrategyChar.generated.h"

 

UCLASS(Abstract)

class AStrategyChar : public ACharacter, public IStrategyTeamInterface

{

GENERATED_UCLASS_BODY()

 

/** How many resources this pawn is worth when it dies. */

UPROPERTY(EditAnywhere, Category=Pawn)

int32 ResourcesToGather;

 

/** set attachment for weapon slot */

UFUNCTION(BlueprintCallable, Category=Attachment)

void SetWeaponAttachment(class UStrategyAttachment* Weapon);

 

UFUNCTION(BlueprintCallable, Category=Attachment)

bool IsWeaponAttached();

 

protected:

/** melee anim */

UPROPERTY(EditDefaultsOnly, Category=Pawn)

UAnimMontage* MeleeAnim;

 

/** Armor attachment slot */

UPROPERTY()

UStrategyAttachment* ArmorSlot;

 

/** team number */

uint8 MyTeamNum;

[以下のコードは省略します]

};

このヘッダでは、ACharacter から派生した新たなクラス AStrategyChar が宣言されています。UCLASS() が使われることによって、そのクラスがリフレクションされるように指定されています。また、C++ の定義の内部でマクロの GENERATED_UCLASS_BODY() にも関連づけられています。GENERATED_UCLASS_BODY() / GENERATED_USTRUCT_BODY() マクロは、追加の関数と typedef をクラス本体に注入するので、リフレクションされるクラスまたは構造体の中で必要となります。

最初に表示されているプロパティは、ResourcesToGather です。これは、EditAnywhere と Category=Pawn によってアノテーションされています。それによって、このプロパティがエディタのどの詳細パネルでも変更できることになるとともに、Pawn のカテゴリに表示されることになります。アノテーションされている関数で BlueprintCallable とカテゴリが付いたものが 2 つありますが、これは、ブループリントから呼び出して使うことができるという意味です。

MyTeamNum の宣言から分かるように、リフレクションされるプロパティとリフレクションされないプロパティを同じクラスで混在させても構いません。ただし、リフレクションに依存するどのシステムからも、リフレクションされていないプロパティは見えないので注意してください (例: リフレクションされていない UObject の生のポインタを保存することは、ガベージ コレクターによって参照が認識されないため、たいていの場合危険です)。

指定子キーワード (EditAnywhere や BlueprintCallable など) はそれぞれ、意味と使用法に関する短いコメントが付けられて、ObjectBase.h の中で説明されています。キーワードの動作が不明な場合は、Alt+G を押すことによって、ObjectBase.h の定義が開かれることになっています。(これらのキーワードは、正式な C++ のキーワードではありませんが、インテリセンスまたは VAX はその違いを無視するか理解しないようです。)

より詳しい情報については、「Gameplay Programming Reference」(ゲームプレイ プログラミング レフ