前回Enumを使った簡単なメモを書きました。
今回はWidgetで応用してみようと思います。
コンソールゲーム想定なので、マウスは非対応です。
UMGのコンポーネントは使いません。Ver 4.11でゲームパッドにも対応したようなことが公表されていた気がしますが、まだ攻略できてないので後日・・・
まずはテクスチャ。
左がRGBで、右がアルファチャンネル。32bitのTargaです。
↑の画像は2倍に拡大してます。
これをコンテンツブラウザにドロップして、テクスチャアセットとしてインポートします。設定詳細は以下。圧縮での劣化を防ぐために圧縮設定は UserInterface2D を選択。
(下図のEditor Iconのとこ)
これをマテリアルに組み込みます。
テクスチャのUV関係をパラメータでいじるので、以前の記事で書いたマテリアルファンクションを利用してます → UVSetParamノード。
64x64のパターンを横に2個くっつけた状態なので、表示したいのは半分です。
TilingのU方向は 0.5を固定でつないでいます。
ではWidgetを用意します。
コンテンツブラウザで右クリック User Interface > Widget Blueprint を取り出したら編集開始。
キャンバスに3つのパーツを配置します。
TextBlockは、Detailsタブの一番上部に名前を付けるフォームがあって、すぐ右に is Variable というチェックボックスがあるので、ここにチェックを付けておきます。
左の白い■は、64x64のサイズです。これにさっき作っておいたマテリアルをセットします。DetailsタブのAppearance > Brush > Image のところです。
次に
見た目に2つの状態をアニメーションで用意します。
DEFAULT はそのまま通常の状態で、FOCUS も言葉どおりハイライトされている状態を表します。適当にカラー等の変化させて記録してやります。
(私は、変数名と区別するために、アニメーション名はすべて大文字で命名するようにしています)
このへんで、編集モードを Graph に変えます。
チェックボックスの状態を保持しておく変数を1つと、状態を切り替える関数を4つ用意します。
変数はBoolean型にします。初期値は false です。
関数は、ラベルテキストを変更するものと、見た目に DEFAULT と FOCUS を切り替えるものと、チェックを付けはずしするものの4つです。
まずはラベルテキストを変更する関数。
引数はString型で1つ。戻り値は無し。
次に見た目を切り替える関数2つ。
アニメーションの再生中に別のアニメーションを再生すると、場合によってはおかしなブレンド結果になって意図どおりの結果にならないことがあるので、保険の意味をこめてStop Animationノードを置いています。
で、最後がフラグをスイッチする関数。
とその前に、準備を忘れるとこでした。
マテリアルインスタンスダイナミックを作っておきます。
EventConstructにつなぐと、スポーン(Add to Viewportとか)した時、真っ先に再生してくれます。
そのタイミングで作成します。ついでに DEFAULTのアニメーションを再生しておきます。
作ったマテリアルインスタンスダイナミックはPromote to Variable(変数に昇格)します。(右端)
で、フラグをスイッチする関数を作ります。
この関数は、呼ばれるたびにフラグを反転し、最終的にマテリアルのパラメータを変更します。1本道にしたくてコンパクトな構成にしています。普通に分りやすく並べると多分下のようになるかと思います。
以上でWidgetは完成です。
画面に表示してキー操作を反映するとこを作っていきます。
キー入力を使ってテストするので、シンプルにレベルブループリント内でやります。
まずは、EventBeginPlayから始めます。
前回書いたように、作ったEnumアセットは、ForechLoopで利用できます。
CreateWidgetノードで、用意したWidgetを表示する準備をします。ForeachLoopによって複数のWidgetが生み出されるのでそれを配列にストックするようにします。
まず、右端のReturnValueの青いPINから、ドラッグしてPromote to Variable(変数に昇格)を選択します。
できたばかりのこのセットノードをグラフから削除します。
配列型に変更する際に、警告がいっぱい出て面倒だからです。
(Variablesのリストからは消さないでください)
これを配列型に変更します。
名前もいい感じに変更したら、改めてこの配列をグラフにGetで置いて、Addノードとつなぎます。
あとはいつも通り、Add to Viewport につないで、ForeachLoopノードのEnumValueにPINから、表示座標計算用にInteger型にキャストして、ラベルテキスト用にString型にキャストしてつないでいきます。
Enumに書いてある内容を元に、
ループ処理をしていきつつ、CreateWidget して並べながらラベル名をセット。
という流れです。
次にフォーカスを切り替えるためのIndex管理用の変数を用意します。
EnumのForeachLoopがWidgetを並べ終えたら、仕上げにフォーカスを当ててやります。これが、ユーザーにとってカーソルとなります。
並べ終わってからなので、CompleteのPINからひっぱって下図のようにつなぎますが、SetFocus関数はWidgetの中に作った関数なので、①~④の番号順でノードを置いていくとスムーズにいくと思います。⑤でフォーカス位置管理用の変数をつなぎます。
ここで、フォーカス位置を変更するための関数を用意します。
引数は一つでInt型。
この引数で次に移行するカーソル位置(未来)を受け取ります、最初フォーカス位置管理用の変数はまだ前の値(過去)のままなので、すぐにDEFAULT状態にします。
引数をセットして更新したら後はそれをFOCUS状態にすれば完了。
関数ができたので、キー入力イベントを3つ用意します。
まずはフラグをスイッチするためのやつで、とりあえずスペースキーにします。
この状態で再生してみるとスイッチの動作を確認できます。
最後の仕上げです。
カーソルキーの上と下を使うことにします。
どちらも最終的にフォーカス切り替え関数に次のフォーカス位置を計算して渡しています。
カーソルの移動が3つ以上になったらループした方がUIとしては使い勝手がいい感じになります。
プラス方向のループについては %(剰余)ノードを使ったらラクちんです。マイナス方向の場合は%は使えないので、今回はセレクトノードを使いました。
この%とSelectノードに、4とか5とかの数値を入れていますが、マジックナンバーというやつで、あとでバグのきっかけになったり、時間が経つと何の値?ってなるので、本当はEnumからForeachLoopで取り出してWidgetを並べる際に数をカウントしておいて利用するのがベストです。ToInt(byte)でキャストしてる箇所で用意しておいた変数に入れていくとよいと思います。
操作と見た目についてはひとまず完成にします。
Enumアセットで管理することで、リスト項目の数や内容が変わった際のメンテナンスコストが大幅に小さくできます。
ブループリントの中に配列で持ってしまうことも可能ですが、他のスタッフが見た時に解析に時間がかかってしまうかもしれないです。
ということで次回もう少しだけ手を入れようと思います。