Unreal Engineの基本的な知識があまりないので、機能紹介も兼ねている機能別サンプルのブループリント通信の中身を見て、複数のブループリント間でどうやってやりとりしたらいいのか見てみた (要はカスタムイベント、イベントディスパッチャー、ブループリントインターフェース)。

確認したバージョン:UE5.2.1
ダウンロード・動かし方
- UEマーケットプレイスのContent Examples in UE Feature Samplesをダウンロードし、UEでプロジェクト作成して起動
- コンテンツブラウザのContent/Maps/Blueprint_Communicationをダブルクリックで開く
機能別サンプルのレベルの構造
- 部屋全体はレベルのアウトライナーに配置された
BP_DemoRoomで構築される- ブループリントクラスは
Content/Global/DemoRoom/Blueprints/BP_DemoRoomにある - コンストラクションスクリプト で自分の
Redraw関数を呼び出し、変数に従って部屋を構築する(プロシージャル) S_RoomSettings構造体型の配列Roomsが各部屋の情報(Length,Width,Heightなど)で、変数がpublicになっているのでレベルの詳細パネルで変数の値を書き換えるとそれに伴って部屋が再構築されるTestRoomというレベルもあるので、そちらも見てみるとよいかも
- ブループリントクラスは
- 機能ごとのブースは
BP_DemoDisplayをベースに作成される- 同じくコンストラクションスクリプトで、
TitleやDescriptionなどが詳細パネルから設定されて反映されるようになっている
- 同じくコンストラクションスクリプトで、
- ブースで説明する要素はそれとは別にフォルダ分けされずにずらっと並べられている
動作の調べ方
- レベル上に配置されているアクターから調べたいものを選択し、アウトライナーのTypeにある「Edit BP_~」をクリックでそいつがどのBPクラスかわかるので、そのブループリントクラスのイベントグラフを見てどういう処理が書かれているかを調べる
- 他には必要だったらレベルブループリントやポーン側でどう処理してるかを見る
ブースごとの内容
1.1 Basic communication with a target blueprint
方法:対象アクターの変数を持っておき、カスタムイベントを呼び出す
説明文:「この例には、カスタムイベントを介してライトブループリントのオンとオフを切り替えるボタンブループリントが含まれています。 プレイ中にボタンに近づくと、有効になります。」 (This example features a button Blueprint that toggles a light Blueprint on and off via a custom event. Approach the button while playing to activate it.)
- ボタンのクラス
BP_ButtonLight_Bulb_Basic側のイベントOnComponentBeginOverlap,OnComponentEndOverlapでプレイヤー(ポーン)とのオーバーラップを検知して、ボタンの発光と電球のオンオフをしている BP_Light_Bulb_Basic型の変数Target lightがpublicになっていて、レベルに配置されたアクターBP_Generic_Buttonの詳細パネルで対象のアクターが設定されていることで、それに対してカスタムイベントが呼び出される
1.2 Blueprint communication via actor casting
方法:対象アクターの変数を持っておき、カスタムイベントを呼び出す
説明文:「この例では、バッテリーを接続することで電球ブループリントのオンとオフが切り替わります。 電球はオーバーラップイベントを使用してバッテリーブループリントとの接触を検出し、それに応じてオン/オフになります。」 (In this example, a lightbulb Blueprint is toggled on and off by connecting a battery. The lightbulb uses an overlap event to detect contact with the battery Bluerpint and turns on/off accordingly.)
BP_Button_Batteryクラスがオーバーラップを検知して、BP_Battery型の変数Target batteryに設定されたアクターにMove up/downカスタムイベントを送り、上下移動させる- バッテリーが移動したことにより、電球
BP_Light_Bulb_Battery_Powered側でオーバーラップを検知したら、自分のToggle Lightカスタムイベントを呼び出し、マテリアルの色とライトのIntensityを変更する BP_BatteryのElectricity value変数を見て明るさを決めている
1.3 Blueprint communication via actor casting to child Blueprint
方法:対象アクターの変数を持っておき、カスタムイベントを呼び出す
説明文:「これらの電球ブループリントは、異なる種類のバッテリーが接続することでオン/オフになります。 各バッテリーは同じ親ブループリントから派生していますが、異なるエネルギー値を持っていてライトの明るさに影響を与えます。」 These lightbulb Blueprints are turned on/off by connecting different types of batteries. Each battery is derived from the same parent Blueprint, but has different energy values that affect the brightness of the light.
- 1.2と同じだけど、3種類のバッテリーでそれぞれライトの明るさが変わる
BP_Batteryを親に持つBP_Battery_Small_ChildとBP_Battery_Big_Childがそれぞれ指定されている- タイトルが “casting to child Blueprint” となっているが別に
Small_ChildやBig_Childにキャストしているわけではなさそう
- タイトルが “casting to child Blueprint” となっているが別に
- バッテリーのパワーやメッシュの変更だけだったら
BP_Batteryに変数が用意されていてレベルのアクターの変数の設定で対応できると思うんだけど、わざわざ子クラスを作るのはなにか意味があるんだろうか?
1.4 Communicating with all actors of a specific class
方法:レベルに存在する特定クラスのアクターすべてにカスタムイベントを呼び出す
説明文:「この電球ブループリントたちはすべて、1つのボタンでオンまたはオフになります。 ボタンブループリントは、電球クラスのすべてのインスタンスを検索し、それぞれのインスタンスで「Toggle light」カスタム イベントを呼び出します。」 (This collection of lightbulb Blueprints are all turned on and off by one button. The button Blueprint finds all instances of the lightbulb class and calls the “Toggle light” custom event in each of them.)
- ボタンのクラス
BP_Button_Light_Bulb_PulseでGet All Actors Of Classノードを呼び出して、レベルに存在するすべてのBP_Light_Bulb_Pulse型のインスタンスを列挙して操作対象にする- 複数の対象に対して
ForEachLoop→Cast To→個別にカスタムイベント呼び出し - 後の3.1のように(カスタムイベントとブループリントインターフェースという違いはあるが)、ループせずに一括対象にもできる模様
- 複数の対象に対して
- クラス
BP_Light_Bulb_PulseのカスタムイベントToggle lightで処理 - 電球の明るさの時間変化はタイムラインで行っている
2.1 Using an Event Dispatcher function to call an event in the Level Blueprint
方法:イベントディスパッチャーの呼び出しをレベルブループリント側で処理する
説明文:「これはイベントディスパッチャー機能を介して電球ブループリントのオンとオフを切り替えるボタンブループリントの例です。 このボタンはイベントディスパッチャーを呼び出し、レベルブループリントでイベントを起動してライトのオンとオフを切り替えます。」 (This is an example of a button Blueprint toggling a lightbulb Blueprint on and off via an Event Dispatcher function. The button calls the Event Dispatcher, which fires the event in the Level Blueprint to toggle the light on or off.)
- ボタンのクラス
BP_Button_Dispatchでオーバーラップを検知してButton toggledイベントディスパッチャーを呼び出す - レベルブループリントのイベントグラフに
Button toggledを受け取るノードが設定されていて、対象の電球BP_Light_Bulb_Basic2のToggle Lightカスタムイベントを呼び出して制御する - イベントディスパッチャーの
Variable TypeがMulticast Delegateになっていて(固定されている)、レベルブループリントのイベントグラフに直接ノードが追加できている- 対象のアクターがレベルに配置されてるから?レベルのブループリントのイベントグラフから直接設定できる。レベルブループリントの
BeginPlayでバインドする、といったことをする必要はない。
- 対象のアクターがレベルに配置されてるから?レベルのブループリントのイベントグラフから直接設定できる。レベルブループリントの
- この場合、レベルがお互いの関係を知っていて関連付けている
2.2 Binding an Event Dispatcher function to a custom event
方法:イベントディスパッチャーにバインドして、呼び出しを受け取る
説明文:「この例では同じボタンブループリントが回転アニメーションを開始および停止します。 この場合、回転ブループリントは、レベルブループリントを使用する代わりに、ボタンのイベントディスパッチャー機能を内部でカスタムイベントにバインドします。」 (In this example, the same button Blueprint starts and stops a rotating animation. In this case, the rotating Blueprint binds the button’s Event Dispatcher function to a custom event internally, instead of using the Level Blueprint.)
- 2.1と同じ
BP_Button_Dispatchクラスだけど、電球(BP_Spinning_Loop_Dispatch)側がBeginPlayイベントでイベントディスパッチャーにカスタムイベントをバインドしている - この場合、電球側がボタン側を知っていて関連付けている
2.3 Binding an Event Dispatcher to a custom event on spawn
方法:イベントディスパッチャーにバインドして、呼び出しを受け取る
説明文:「このボタンを押すと爆弾のブループリントが生成されます。 このボタンは爆弾ブループリントが爆発したことを通知するディスパッチイベントを受信するまで、1回だけ押すことができます。」 (This button will spawn a bomb Blueprint when pressed. The button can only be pressed once, until it received a Dispatch Event notifying it that the bomb Blueprint has exploded.)
- ボタンは
BP_Button_Dispatch_Bombで、オーバーラップで自分のActivateカスタムイベントを呼び出して爆弾をスポーンする。 - スポーンした爆弾(
BP_Bomb)のイベントディスパッチャーBomb Explodedにカスタムイベントをバインドして爆発終了を検知する。爆発するまでの間は2つ目は作られないようにする(Button Enabled変数で管理)。 - イベントディスパッチャーのバインドのやり方自体は2.2と特に変わらない。
3.1 Basic communication using Blueprint Interface function)
方法:アクター配列変数に対してブループリントインターフェースの関数を呼び出す
説明文:「この例ではブループリントボタンはブループリントインターフェースメッセージを介してさまざまなブループリントの配列をアクティブにします。 各ブループリントは異なるクラスですが、同じブループリントインターフェース イベントを使用しているため、最初に各クラスにキャストする必要がなく、単一の関数ですべてをアクティブ化することができます。」 (In this example, a button Blueprint activates an array of different Blueprints via a Blueprint Interface message. Although each Blueprint is a different class, the fact that they employ the same Blueprint Interface Event makes it possible to activate them all with a single function, without the need to cast to each class first.)
- ボタン
BP_Button_InterfaceにActor配列型の変数Target Blueprintsがあり、オーバーラップでBPI_Player_Interactionsブループリントインターフェース(以下BPインターフェース)のPushed Button関数を呼び出すActor配列をForEachLoopノードでループしてCast Toとかせずに、直接与えられる模様- イベントグラフで右クリック>「Pushed Button」で選択できる
- インターフェースを実装しないアクタークラスの場合は無視されるっぽい
Target Blueprints変数に設定されている3つのBPクラスBP_Light_Bulb_Interface,BP_LED_Inteface,BP_Spinning_LogoはどれもBPI_Player_Interactionsを実装している- BPクラスがインターフェースを実装しているかどうかは、「⚙️Class Settings」をクリック>Interfaces>Implemented Interfaces に登録されていることを調べる。またMy Blueprint>INTERFACES に所定のインターフェースの関数があることを確認する。
3.2 Communication using a Blueprint Interface function
方法:オーバーラップしたアクターが特定のBPインターフェースを持っていたら呼び出す
説明文:「この例ではブループリントボタンは、BPインターフェースメッセージを介してさまざまなブループリントの配列をアクティブにします。 各ブループリントは異なるクラスですが、同じBPインターフェースイベントを使用しているため、最初に各クラスにキャストする必要がなく、単一の関数ですべてをアクティブ化することができます。」 (In this example, a button Blueprint activates an array of different Blueprints via a Blueprint Interface Message Although each Blueprint is a different class, the fact that they employ the same Blueprint Interface Event makes it possible to activate them all with a single function, without the need to cast to each class first.)
- 今までのサンプルと違いオーバーラップで電球がオンオフされるんではなく、オーバーラップでテキスト表示され、対象のレバーをマウス操作で電球がオンオフされる
- ポーン
MyCharacter_BP_Commsでマウス左クリック時にGet closest interactive actor関数でオーバーラップしているアクターの中からDoes Implement InterfaceノードでBPI_Player_Interfactionsを探し、水平距離が一番近いものをActor To interact With変数に格納 TickイベントでinteractingだったらBPI_Player_InteractionsのGrab Interact関数を呼び出し、対象の各クラスで処理される(そっちの処理はあまりよく理解できなかった…)- 内容的には3.1 との違いがわからず、
Pushed buttonに比べてGrab Interactは引数や戻り値がある、という程度?
3.3 Communication using a Blueprint Interface function
方法:オーバーラップしたアクターが特定のBPインターフェースを持っていたら呼び出す
説明文:「この例では発射物の衝突を処理するためのBPインターフェースメッセージの使用を示します。 発射体ブループリントは衝突時に球体ブループリント上のインターフェース関数を呼び出し、各球体はインターフェースを介して渡された情報に対して異なる反応を示します。」 (This example demonstrates a Blueprint Interface Message use for handling projectile collisions. The projectile Blueprints call an Interface function on the sphere Blueprints when they hit, and each sphere responds differently to the information passed through the Interface.)
- 近くに来るとマウス左で火、マウス右で水を撃てるようになり、3種類の球に当たるとそれぞれ異なる反応をする
- 範囲かどうかはレベルに配置された
TriggerBoxとのオーバーラップをレベルブループリントのイベントグラフで取得してポーン(MyCharacter_BP_Comms)のPowers Enabled変数を書き換える
- 範囲かどうかはレベルに配置された
MyCharacter_BP_Commsでマウスクリック時にShoot fireballまたはShoot waterカスタムイベントで、SpawnActorノードでBP_Projectile_FireまたはBP_Projectile_Waterを生成- どちらも
ActorBeginOverlapでオーバーラップしたアクターに対してBPI_Elemental_ProjectilesインターフェースのElemental Damage関数にパラメータHeatとWaterを渡して呼び出す - 3つの球はそれぞれ
BP_Metal_Sphere,BP_WoodSphere,BP_Ice_Sphereクラスで、Elemental Damageインターフェース関数を実装、パラメータに従って変数を変更し、Tickイベントでマテリアルのパラメータを設定して火や水の影響を表示に反映させている
まとめ
- ブループリント間でやり取りするには カスタムイベント、 イベントディスパッチャー、 BPインターフェース の3通り
- 実際には他にも 関数呼び出し や変数参照・変更もあるっちゃある
- 各方法の特徴
- カスタムイベント:呼び出し元が呼び出し先のことを知っている(依存関係)
- イベントディスパッチャー:呼び出し元が呼び出し先のクラスを判定して処理を分ける、ということをしなくて済む
- 呼び出し元と呼び出し先が直接は無関係でいられて、バインドするやつが双方に依存する
- バインドは不特定多数で可能
- BPインターフェース:呼び出し元と呼び出し先がそれぞれBPインターフェースに依存するが、お互いは直接は独立
- インターフェース(や関数呼び出し)はイベントと違って戻り値を受け取れる、という違いがある
- 関数の場合
Delayノードなどの時間経過を含むノードは使えない。インターフェースの場合も戻り値がある場合は使えない?っぽい。戻り値がない場合には歯車が黄色になってイベントグラフ上に置かれる?
- 所感
- 配列に対して一括でカスタムイベントやBPインターフェースの呼び出し、またアクターに対してキャストせずに呼び出せることを知った
- 部屋がコンストラクションスクリプトで作られていてサイズなどを変更すれば対応できてすごいんだけど、 メッシュの構築などをノードで組むのは大変そう…