読者です 読者をやめる 読者になる 読者になる

GameProgrammar's Night

ゲームプログラム系の覚え書き

UE4 イベント・関数・マクロ・インターフェイスの違いと使い分け

UnrealEngine4 Blueprints

qiita.com

この記事は、UE4 AdventCalender 18日目の記事です。

 BPには、イベント・関数・マクロ・インターフェイスと手続きの実装手段が豊富にあります。
 BPはオブジェクト指向言語ではありますが、オブジェクトより手続きを重視した思想になっている現れだと個人的に思っています。
 とはいえ、手続きの実装手段が多すぎて、結局どれで実装すれば良いのかが、わかりにくいというのも確かです。そこで、各手続きの機能的な違いと使い分けについて紹介したいと思います。

主な機能一覧表

イベント 関数 マクロ インターフェイス
入力ピン 1個 0~1個 0個以上 1個
出力ピン 1個 0~1個 0個以上 1個
引数 0個以上 0個以上 0個以上 0個以上
戻り値 なし 0個以上 0個以上 0個以上
アクセス制御 public public
procted
private
private public
オーバーライド 不可
ノード制限 なし あり なし 実装方式による
EventDispatcherへのbind 不可 不可
特徴 ネットワーク越しに呼べる いわゆるメソッドに一番近い Lispのマクロのような
Functorのような
ダックタイピング

手続き解説

イベント

 イベントは、BPにおける手続き実装の基本です。
 もっとも制限のない手続きのため、戻り値がいらないならイベントを使いましょう。

 イベントの大きな特徴は、ネットワーク越しに呼べることです。
docs.unrealengine.com

 自動でRPC機能がつくので、これだけで、ネットワークゲームがある程度作ることができます。 

関数

 戻り値が必要な時は、関数を使います。
 唯一アクセス制御をコントロールできますので、アクセス制御が必要な時も関数を使います。LatentノードやTimelineノードなど一部使えないノードが存在します。

 関数はPureフラグをオンにすることで実行ピンを省略することができます。値の取得のみで済む場合は、オンにすると良いでしょう。

 他のクラスベース言語経験者で、BPのことがよくわからない内は、関数で実装して、関数ではできないことはイベントにするというやり方でも良いと思います。

マクロ

 ノードをまとめて整理したり、部分的に使い回すのに使います。インライン化機能もついており、実行時にはノードが展開されます。
 最大の特徴は、複数の入出力ピンを使えることです。

f:id:katze_7514:20161217004936j:plain
 上記のマクロは、プレイヤーのPawnとの距離に応じて、出力ピンが実行されます。
 ちなみに「ノードの折りたたむ」はマクロにすると同じです。

 マクロはprivateになりますので継承先では使えません。継承先でも使いたい時は、イベント・関数として実装しなおすか、MacroLibraryを使います。ただ、MacroLibraryに実装すると逆に継承先でしか使えませんので、イベント・関数で実装にした方が良いかもしれません。
 また、マクロ内部ではブレイクポイントをおけませんので、はじめからマクロとして作るとデバッグが大変なこともあります。

 名前から、C言語系のプリプロセッサのマクロかなと思うかもしれませんが別物です。おそらくですが、Lispマクロを参考にしているのだと思います。
 Sequenceノードと組み合わせることで継続のようなこともできますし、マクロのローカル変数は実行終了後も値を維持しますのでFunctorのような挙動もします。
 マクロだけで1冊本が書けそうなぐらい様々なことがでできます。

インターフェイス

 インターフェイスは、キャストなしに呼ぶことができます。そのため、クラス間の依存度を下げるのに使います。テンプレートやジェネリクスのないBPでダックタイピングをするための手続きです。
 わかりやすい使い所は、Overlapイベントなどエンジンが用意しているイベントです。
f:id:katze_7514:20161217012833j:plain
 エンジンが用意するイベントは、引数がActorなど汎用的な型ですので、Interfaceにしておくと楽になります。

f:id:katze_7514:20161217011007j:plain

 インターフェイスの呼び出しは、右上に手紙マークがつきます。
 右クリックメニューから選ぶ時は、Messageとついてるのを選びます。
f:id:katze_7514:20161217012109j:plain

 クラス間の依存度下げることは、コンパイルが早くなるだけでなく、エディタのクラッシュ率やバグを踏む可能性も下げますので重要です。

 インターフェイスの実装は、戻り値がない場合はイベント、戻り値がある場合は関数として実装します。
 なお、インターフェイスはデフォルト実装が直接はできませんので、場合によっては他の手続きで実装した方が楽なこともあります。

明日は

 明日は、hima_zinnさんの「UE4のショートカットをカスタマイズして開発効率を上げる」です。