たすブログ

近況:4 告知:4 技術ブログ:2 な割合です

BPをテキストエディタに貼れるのならテキストエディタでBP書けるんじゃないのチャレンジ

この記事は「Unreal Engine (UE) Advent Calendar 2021」16日目となります。

qiita.com

 


・はじめに

さて、皆様ご存じの通り、ブループリントで書いた処理をコピーして
テキストエディタに貼り付けると、テキストに変換され、
逆にテキストエディタからUEエディタに貼るとBPに変換されます。

ということは。
テキストだけでBPある程度かけるのでは!?

ということで、テキストエディタ上に貼られたBPの中身を軽く読んで、
BPをテキスト編集する際に、最低限ここを触ればいいのではという部分を調べました。
実際に編集する機会は、置いておくとして……!


・目次

内容としては以下の流れとなります。

  • ノードの構成
  • get/set変数の取り方
  • 標準的なノードの呼び出し
  • ピン
  • ノード接続
  • カスタムイベント
  • 最後に

※記事内で全てのテキストを説明するととても多くなってしまうため
省略できる箇所(デフォルト値で補間される箇所)は省略して
最低限の部分だけで試したものとなります。

また、定義元のファイルを記載していますが全部は調べてないので
別の箇所にもある可能性もある前提でお願いします。

では行きましょう…!


・ノードの構成

まず最小構成としてノードの置き方です。
Begin Object Class=…~End Objectで挟んだものがひとつのノードになります。

Nameは省略可能ですが、ピン接続時に必要になるので入れておくと良いです。

例えば変数のGetとSet(中身なし)を置く場合は以下の形。

//getObject
Begin Object Class=/Script/BlueprintGraph.K2Node_VariableGet Name="test1"
End Object
NodePosX=0
NodePosY=0
End Object
//setObject
Begin Object Class=/Script/BlueprintGraph.K2Node_VariableSet 
NodePosX=200
NodePosY=0
End Object

f:id:tasuya:20211214154909p:plain

中身がないGetとSetが置けました

NodePosX/NodePosYで座標指定が出来ますが、
これはBPにペーストした時点でクリックした位置が原点になるので、
手書きでやる場合は「並べるときにずらすオフセット」と思えばよさそうです。

ちなみに座標を揃えて同じノードを複数貼ろうとすると、同一と判断されてひとつしか貼られません。
良く出来てる。


・get/set変数の取り方

上記get/set命令は「どの変数が対象」かは含まれていないので、
どれを参照するかを追加する必要があります。

変数宣言はBP上でする必要があるので、
あらかじめ宣言しておいてそれをVariableReferenceのMemberNameに入れると
その変数が参照されます。

 

例えばBP上にfloat floatTestの変数を用意した上で下記をペーストすると

floatTestのgetが配置されます。

Begin Object Class=/Script/BlueprintGraph.K2Node_VariableGet 
   VariableReference=(MemberName="floatTest",bSelfContext=True)
End Object

 

f:id:tasuya:20211214160259p:plain

宣言されている変数名と一致していれば取れます

bSelfContextはFalseにすると左側に親を指定できるようになりますが
その場合はピン設定もちゃんと書かないと取得できないので今回は飛ばします。


・標準的なノードの呼び出し

さて、突然でてきたGetとSetですが、これら基本的な命令は
\Engine\Source\Editor\BlueprintGraph\Classes\
K2Node_~~.hという形でヘッダー名がそのまま命令の名前になっているものがあります。
これらの名前をClass=/Script/BlueprintGraph.~~の部分に入れてペーストしてやると概ね呼び出すことができます。
LoadAssetとかSpawnActorとかStructMemberGetとか。
BranchはK2Node_IfThenElseでした。

f:id:tasuya:20211214162410p:plain

UE4のIfはブランチですと説明したりしますがIfでした

PrintStringやfloat+float等の関数・イベントは
Class=/Script/BlueprintGraph.K2Node_CallFunction 
で呼び出します。
FunctionReferenceのMemberParentにヘッダー、MemberNameに関数名を入れます。

Begin Object Class=/Script/BlueprintGraph.K2Node_CallFunction
   FunctionReference=(MemberParent=Class'"/Script/Engine.KismetSystemLibrary"',MemberName="PrintString")
   EnabledState=DevelopmentOnly
End Object

f:id:tasuya:20211214163010p:plain

EnabledState=DevelopmentOnlyは「開発のみ」のオンオフなので
省略すると「開発のみ」が外れたPrintStringも置けます。

関数が定義されているヘッダーは
Engine\Source\Runtime\Engine\Classes\Kismet\
にありますので、ここから探すと良さそうです。

PrintStringはKismetSystemLibrary.hに、
floatの足し算(Add_FloatFloat)はKismetMathLibrary.hにありました。


・ピン

引数や実行ピンは命令の宣言側で定義されているので、
呼び出し側で省略してもデフォルト値が入る場合が多いため
ここまで省略してきましたが、
必要な場合はピンごとにCustomProperties Pin()で設定します。

ピン一つに対しての設定項目が多いため
全て書くとそれだけでひと記事が必要となってしまいますので
最低限必要な部分として以下あたりを押さえておくとよさそうです。

  • PinId:接続で使用する自分のピンのID 接続先になる場合に使用
  • Direction:入力ピンか出力ピンかの判別 "EGPD_Output"なら出力(右側)ピン
  • PinName:ピンの名前
  • PinType.PinCategory:ピンの種類 "exec"なら実行ピン
  • LinkedTo:このピンから接続する先のノード名(BeginObjectで指定したName)とつなぎたいPinId
  • DefaultValue:引数等のデフォルト値

DirectionのEGPD_Output/EGPD_Inputなど、ノード関連のenumは
\Engine\Source\Runtime\Engine\Classes\EdGraph\EdGraphNode.h
にて定義されているようです。

set floatTestを例にすると

Begin Object Class=/Script/BlueprintGraph.K2Node_VariableSet
   VariableReference=(MemberName="floatTest",bSelfContext=True)
   CustomProperties Pin (PinId=A0000000000000000000000000000000,Direction="EGPD_Output",PinType.PinCategory="exec")
   CustomProperties Pin (PinId=B0000000000000000000000000000000,PinName="floatTest",PinType.PinCategory="float",DefaultValue="10.0")
End Object

の形で

  • A0000000000000000000000000000000:右側出力ピン側の実行ピンID
  • B0000000000000000000000000000000:左側入力ピンのfloat ピンのIDとデフォルト値を10に設定

となります。


・ノード接続

ノードの接続は、

  • 接続元の出力ピン(EGPD_Output)のLinkedToに接続先のPinId
  • 接続先の入力ピンのLinkedToに接続元のPinId

の形で、双方に接続するピンを指定する形で接続されます。

PinIdは32桁固定のようですので、桁数だけは揃えるようにしてください。

//接続元のPrintString
Begin Object Class=/Script/BlueprintGraph.K2Node_CallFunction Name="print1"
   NodePosX=0
   NodePosY=0
   FunctionReference=(MemberParent=Class'"/Script/Engine.KismetSystemLibrary"',MemberName="PrintString")
   CustomProperties Pin (PinId=B0000000000000000000000000000000,PinName="then",Direction="EGPD_Output",PinType.PinCategory="exec",LinkedTo=(print2 A0000000000000000000000000000000))
End Object
//接続先のPrintString
Begin Object Class=/Script/BlueprintGraph.K2Node_CallFunction Name="print2"
   NodePosX=200
   NodePosY=0
   FunctionReference=(MemberParent=Class'"/Script/Engine.KismetSystemLibrary"',MemberName="PrintString")
   CustomProperties Pin (PinId=A0000000000000000000000000000000,PinName="execute",PinType.PinCategory="exec",LinkedTo=(print1 B0000000000000000000000000000000))
End Object

f:id:tasuya:20211215001642p:plain

実行ピンを相互指定した状態

・カスタムイベント

最後にカスタムイベントの作り方です。
ClassをK2Node_CustomEventにしてCustomFunctionNameにイベント名をつけると作成できます。
ピンは出力ピンでdelegate(右上の赤四角)とexec(実行ピン)は最低限入れておくようにしてください。
delegateを省略するとエディタが落ちました。

引数が必要な場合はCustomPropertiesにUserDefinedPinとしてピンを追加してやると設定できます。
引数のタイプはPinType.PinCategoryではなくPinType=(PinCategory="")になります。

Begin Object Class=/Script/BlueprintGraph.K2Node_CustomEvent Name="TestEvent"
   CustomFunctionName="TestCustomEvent"
   CustomProperties Pin (Direction="EGPD_Output",PinType.PinCategory="delegate")
   CustomProperties Pin (Direction="EGPD_Output",PinType.PinCategory="exec")
   CustomProperties UserDefinedPin (PinName="floatParam",PinType=(PinCategory="float"),DesiredPinDirection=EGPD_Output)
End Object

f:id:tasuya:20211215005206p:plain

ここまでやれば基本的な部分は作れるかなあ、というところだと思います。


・最後に

あとはID生成のソース周りもちょっと調べてたんですが、
それはまたの機会に書ければ。

調べ始めたときは「何をやっているんだろう…」と思わなかったか、
と言えば、思った!と強く言い切れますが
実際のところ調べていくうちに「ホンット良く出来てんなあ」と。
省略がすごい出来たので調べるのも簡単でしたし。

BPをテキストで編集する機会自体はあまりないかとは思いますが、
自作スクリプトをノードベースで作る際等の参考としては
この辺りを追いかけるのも良いのかなと。

良く出来てますホント。