[UE4]Unreal.jsでJSのコードに型とフラグ情報を付与する


Unreal.jsプラグインでJavaScriptで作成したものをUE4の世界に認識させるには次の方法が必要になる。

  1. ES2015(ES6)の書き方でクラスを生成
  2. クラス・メソッド・プロパティに 型とフラグの情報を付与
  3. uclass.jsで型とフラグ情報を解析させてUE4側にクラスを認識させる

この「型とフラグの情報を付与」という部分が若干特殊なので説明。

Unreal.jsでの型およびフラグ情報の独自表現

周知の通り、JavaScriptには型表現の方法が基本的にない。一方UE4のUnreal C++ & Blueprintには型がある。Unreal.jsではこの差を埋めるために、コメント中に埋め込まれた型とフラグ情報を解析した上でUE4側に渡す形になっている。

また、Unreal C++独自のマクロ(UPROPERTYなど)での識別子指定もフラグ情報等として表現できる( メタデータ識別子 メタプロパティも一部対応しているようだ)。

以下が、それぞれのUnreal C++マクロに対応するJS側での書き方。

UCLASS

unreal_c++
UCLASS([specifier, specifier, ...], [meta(key=value, key=value, ...)])
class ClassName : public ParentName
{
    GENERATED_BODY()
}
class ClassName /* ClassFlag+ClassFlag+... */ extends ParentClass {
   ctor() {
     // initialization
     // component setup
   }
   properties() {
     // property-declarations
   }
}

class クラス名 /* フラグ情報1+フラグ情報2+... */ {}の形で定義する。

注意点:

  • ES5以前の疑似クラス定義には非対応
    • 文字列解析で処理されているため
  • コンストラクタはctor()
    • ES2015のconstructor()はJS側のコンストラクタ、ctor()はUE4側のコンストラクタとして働く
  • プロパティ(UPROPERTY)はproperties()で定義
  • UClassとして扱うには最後にuclass.jsで解析する必要がある
//transformed into corresponding USTRUCT and UCLASS
let cls = require('uclass')()(global, ClassName);

参考:USTRUCT and UCLASS

UFUNCTION

unreal_c++
UFUNCTION([specifier, specifier, ...], [meta(key=value, key=value, ...)])
ReturnType FunctionName([Parameter, Parameter, ...])
class ClassName{
  //...
  FunctionName([
    Parameter /* PropertyFlag+ParamType */,
    Parameter /* PropertyFlag+ParamType */,
     ... 
  ]) /* specifier+ReturnType */
}

前提としてUCLASSと同時に定義する必要がある(JS的には必ずクラスのメソッド)。

関数名(引数名 /* UPROPERTYのフラグ+引数の型 */) /* UFUNCIONのフラグ+返り値の型 */という形で定義する。「UFUNCIONのフラグ」は関数指定子ということで調べられるが、Unreal.jsのWikiには言及がないのですべて使えるかどうかは不明。

UPROPERTY

unreal_c++
UPROPERTY([specifier, specifier, ...], [meta(key=value, key=value, ...)])
Type VariableName;
Unreal.js
class MyClassName{
  //...
  properties(){
    this.VariableName /* specifier+specifier+...+Type */;
  }
}

前提としてUSTRUCTUCLASSと同時に定義する必要がある。

UPROPERTYマクロは変数プロパティをエディタ上やBlueprint上から扱えるように設定するため設定する頻度が高い。JSで同様にするためにはproperties()メソッドの中で次のように定義する。properties()メソッド以外では定義できないので注意。

this.プロパティ名 /* フラグ1+フラグ2+...+型 */;

なお、ドキュメントには明記されていないがEditConditionなどのメタプロパティも次のような書き方で有効になった。

metaの書き方
properties() {
  //bEditConditionが有効ならエディタ上で編集可能に
  this.EditConditionVariable /* EditAnywhere+Category:condition+EditCondition:bEditCondition+int32*/
  //エディタ上で普段は隠しておく
  this.bEditCondition /* EditAnywhere+Category:condition+AdvancedDisplay+bool */;  
}



USTRUCT

unreal_c++

USTRUCT([Specifier, Specifier, ...])
struct StructName
{
    GENERATED_USTRUCT_BODY()
};
class StructName /* Struct+Specifier+Specifier+... */{
   properties() {
     //property-declarations
   }
}

UStructはJSのクラスを作成したうえで、Structとコメントの最初に記述する。

参考:USTRUCT and UCLASS

補足情報

  • uclass.jsの中では正規表現で文字列解析して変換している
    • Function.toString()でソース文字列を引っ張って解析(コメントも取得できる)
    • なのでここのコードを書き換えるか同様の処理を別のJSでやれば別の記法で型とフラグ情報を付与できる
  • UINTERFACEマクロに相当するものはないっぽい?