【Unreal Engine】機能別サンプルでブループリント間でやりとりする方法を見てみる

2023-09-03

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

Blueprint Communication

確認したバージョン: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 をベースに作成される
    • 同じくコンストラクションスクリプトで、TitleDescriptionなどが詳細パネルから設定されて反映されるようになっている
  • ブースで説明する要素はそれとは別にフォルダ分けされずにずらっと並べられている

動作の調べ方

  • レベル上に配置されているアクターから調べたいものを選択し、アウトライナーの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 lightpublicになっていて、レベルに配置されたアクター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_BatteryElectricity 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_ChildBP_Battery_Big_Child がそれぞれ指定されている
    • タイトルが “casting to child Blueprint” となっているが別に Small_ChildBig_Child にキャストしているわけではなさそう
  • バッテリーのパワーやメッシュの変更だけだったら 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_PulseGet All Actors Of Class ノードを呼び出して、レベルに存在するすべての BP_Light_Bulb_Pulse 型のインスタンスを列挙して操作対象にする
    • 複数の対象に対して ForEachLoopCast 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_Basic2Toggle Light カスタムイベントを呼び出して制御する
  • イベントディスパッチャーのVariable TypeMulticast 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_InterfaceActor 配列型の変数 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_InteractionsGrab 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 関数にパラメータ HeatWater を渡して呼び出す
  • 3つの球はそれぞれ BP_Metal_Sphere, BP_WoodSphere, BP_Ice_Sphere クラスで、 Elemental Damage インターフェース関数を実装、パラメータに従って変数を変更し、 Tickイベントでマテリアルのパラメータを設定して火や水の影響を表示に反映させている

まとめ

  • ブループリント間でやり取りするには カスタムイベントイベントディスパッチャーBPインターフェース の3通り
    • 実際には他にも 関数呼び出し や変数参照・変更もあるっちゃある
  • 各方法の特徴
    • カスタムイベント:呼び出し元が呼び出し先のことを知っている(依存関係)
    • イベントディスパッチャー:呼び出し元が呼び出し先のクラスを判定して処理を分ける、ということをしなくて済む
      • 呼び出し元と呼び出し先が直接は無関係でいられて、バインドするやつが双方に依存する
      • バインドは不特定多数で可能
    • BPインターフェース:呼び出し元と呼び出し先がそれぞれBPインターフェースに依存するが、お互いは直接は独立
      • インターフェース(や関数呼び出し)はイベントと違って戻り値を受け取れる、という違いがある
      • 関数の場合Delayノードなどの時間経過を含むノードは使えない。インターフェースの場合も戻り値がある場合は使えない?っぽい。戻り値がない場合には歯車が黄色になってイベントグラフ上に置かれる?
  • 所感
    • 配列に対して一括でカスタムイベントやBPインターフェースの呼び出し、またアクターに対してキャストせずに呼び出せることを知った
    • 部屋がコンストラクションスクリプトで作られていてサイズなどを変更すれば対応できてすごいんだけど、 メッシュの構築などをノードで組むのは大変そう…