みつまめ杏仁

アンリアルエンジン(UE4)でGUIを作るためにゴニョゴニョしてます。UIデザイナーの皆様の助けになれば幸いです。

複数Widgetの操作処理、こんな感じでどうかな?

アップデートして、4.11.2になりました。

前回の記事で艦これ改のUI設計について偉そうなことを書いてしまいましたが、思うところあって勉強がてらUE4で試してみることにしました。

さすがに今までの記事みたいに作り方~なんてのはボリューム的に大変そうなので、細々と作りつつ途中経過で発見したことや気付いたことなんかをつまんで書いていこうと思います。

 

多くのゲームはいくつもの画面を切り替えて、それぞれの機能に沿って操作します。またメモリの都合などで、すべての画面用アセットを読み込むのはロード時間と天秤にかける必要があって、確実にメモリに置けるかどうかは、開発終盤にならないと確定できません。したがって画面ごとに専用のウィジェットやブループリントを用意して、適宜読み込んだり破棄したりする構造になるのが一般的だと思います。

実にこのいくつもの画面で操作権を切り替えるところが難しい部分で、効率良く作る方法を今まさに模索しているところです。

 

とりあえず今回は、ブループリントインターフェイスと親クラスの使い方で、いい感じの構成ができたので紹介します。まだ実験中ではありますが一例として参考になれば嬉しいです。

 

アセットレベルでの相関イメージ。

 

f:id:hiyokosabrey:20160506001642p:plain

ブループリントインターフェイスとそれをセットした親クラスをひとつ作るだけで、たくさんの子供Widgetたちに操作まわりの処理を書くのがラクになります。

 

 

まず『ブループリントインターフェイス

f:id:hiyokosabrey:20160505230504p:plain

コンテンツブラウザから作ります。

キー入力を処理するための関数をまとめて登録しておきます。関数と言っても名前だけで処理は書くことはできません。とりあえずゲームパッドやキーボードの入力を受け取って処理するための関数として用意します。関数名は適当です。

f:id:hiyokosabrey:20160505232748p:plain

 

 

次に『親クラス』

f:id:hiyokosabrey:20160505231037p:plain

普通にいつも通りに作ります。今回はウィジェットで作ろうと考えているので、WidgetBlueprintにしました。そして大事なのは先に用意したブループリントインターフェイスを登録しておくことです。編集モードをGraphに替えて、ClassSettngsからセットすることができます。

このWidgetには、アクティブかどうかを保持するブーリアン型の変数を一つと、キー入力をチェックしてそれぞれに応じた関数(ブループリントインターフェイスの)を呼び出す関数をひとまず置いておきます。

f:id:hiyokosabrey:20160505233054p:plain

拡大するとこんな感じ。

f:id:hiyokosabrey:20160505233459p:plain

これはInputイベントを使わない方法です。PlayerControllerからWas Input Key Just Pressed ノードを使って、キーを押したかどうかの判定をします。押していたらブループリントインターフェイスの中の関数を呼んでいます。

この関数は各子供のWdgetでEventTick ノードにつないで使います。下図は接続イメージ。右端のノードが上の関数。

f:id:hiyokosabrey:20160505234509p:plain

 

 

これで基本的な準備ができました。

あとは、各子供のWidgetたちが、この親Widgetを ClassSettingsでParent Classとして設定してやることで、親の持ってる関数を継承し自分のものとして利用することができます。

f:id:hiyokosabrey:20160505232242p:plain

 

親から継承した関数を使うには、

f:id:hiyokosabrey:20160505235226p:plain

関数の追加と同じ要領でOverride をクリックすると、ブループリントインターフェイスに登録してあるのと同じ関数名が、リストになって出てきます。これは親クラスにセットしたブループリントインターフェイスが子供のWidgetに継承されているからです。

 

ブループリントインターフェイスの関数は、呼び出しても中身が無ければ、何もしませんし、エラーも出しません。

必要なキー操作に応じた関数を適宜置いて処理を追加してやるだけです。

たとえば、ある画面では、メニュー選択でカーソルの上下移動と、決定&戻るボタン。またある画面ではカーソルの上下左右移動と戻るボタン。のようにそれぞれ必要な操作に合わせた関数を置いて処理が書けるので、柔軟で汎用的な作りが実現できます。

 

 

Widget同士の操作権については、親クラスに用意したフラグで管理します。

子供のWidget内でTickにつないだ入力チェック関数を有効にするかしないかをフラグ(親で用意したブーリアン型の変数)で判定してやります。

 

f:id:hiyokosabrey:20160506004841p:plain

Tick(またはEventTick)は画面に World や Viewport に置かれると常時処理され続けます。 SpawnActor や Add to Viewport された直後に Event Begin Play や、Event Construction が処理されて、そのあとはずーっとTick や Event Tick が動くことになります。おもちゃの水車をイメージすればいいかも。

 

f:id:hiyokosabrey:20160506144005p:plain

子供のWidgetたちの中で、それぞれのTickが流れているので、回ってほしい子供だけをActiveにしてやるのです。

 

 ちなみに『親クラス』は、コンテンツブラウザ上では普通のアセットとして見えていますが、ひとたび『親クラス』として設定されてしまうと、持っているものすべてを子供に引き渡します。そして子供は親の持つものすべてを自分のものとして利用できます。

また同じ親を持つ兄弟姉妹とは、同じ名前の変数や関数を利用することになりますが同じ親というだけで、値は一切共有しません。親が持っていた変数はすでに子供のものになっているからです。

 

この一連の処理で必要なものを、親が持っているので、子供たちは単に親クラスを設定するだけで利用できます。関数名も統一できるし、操作の自由度も子供たちに任せられます。

 

子供一人ひとりに必要なものすべてを入れていく構造だと、子供を増やす際に結構手間がかかります。下手なコピペは事故の元だしかえって手間がかかることの方が多いです。メンテナンスの効率を考えても親クラスを利用するメリットは十分にあると思うのですがいかがでしょう?

 

ではでは 今回はこの辺で~