[第14回UE4ぷちコン]振り返り:メニューUI

概要

    • 無料PluginであるUI Navigationを使った

    • おかわり はくまいさんの解説記事は神

    • 実際便利。オススメ!

UI Navigationとは

Marketplaceで配布されている、GUI作成支援プラグイン。

UI Navigation:Goncas Mage:Code Plugins - UE4 マーケットプレイス

詳しくはおかわり はくまいさんの神記事を参照されたい。

UINavitagion入門 - おかわりのアンリアルなメモ

ありがたや…ありがたや…🙏

使ってみた

プレイアブル版では、簡単なオプションメニューを作った。

どう使ったか

基本的な使い方は上記の解説記事を参考にしつつ、

自分なりにカスタムして使った。

汎用ラベル

単に日本語と英語の説明文を表示するWidget。

これ自体はUI Navigationの機能を使っていない。

Parent ClassもUser Widgetのまま。

テキストとフォントサイズは外から編集できる。

また、「選択された(選択解除された)」際に明度変更する。

ここに拡縮アニメをいれてもいいだろう。

テキストで構成されているが、

もちろんImage一枚で構成しても良いと思う。

というか、そうするつもりで単体のWidgetとして分けたのだが

「動くんならリリースしようぜ」

という囁きがどこからか聞こえたのでそのままリリースした。

汎用アイテム

NavButton内の要素として上記のラベルを持ったWidget。

Parent ClassはUINav Component。

このWidgetは所謂メニュー項目として機能する。

機能的には「ボタン」なのだが、

「押す」機能を持たない場合もあるので「アイテム」と呼んでいた。

これは個人の好みなので、真似しない方がいいかも…

上記のように、IsButton変数で「押せる」かどうかを分けた。

「いや押せないボタンってなんやねん」と思うかもしれないが、

上記Gifで見られるように、「設定」内メニューにおける「映像」と「音響」の項目がそれに該当する。

これらは、Focus(UI Navagation風に言うなら、Navigate To)するだけでサブメニューがSwitchするようになっている。(詳細は後述)

On Navigated系イベントをOverrideして、Toで来た場合にEventで親に知らせる形をとっている。

余談

UINav Component派生Widgetが”NavText”という名前のText Widgetを持っていない場合、

Compileすると”An optional widget binding “NavText” of type Text is available.”というメッセージが出る。

これは文字通りoptionalであって、別にエラーではない。

今回は日本語と英語を併記したかったので、NavTextは使わずに

上記の汎用ラベルWidgetで代用している。

(そのせいで、選択時に文字色を変える機能を自前実装する事になっているのだが…)

オプションボックス

おかわりさんの記事にある通り、

Plugin内にオプションボックスの実装例が存在する。

今回はそれを参考に、

ラベル付きのオプションボックスを作成した。

親クラスは同じくUINav Option Boxを使う。

これによって、選択Indexの定義やClamp処理、

選択項目文字列の定義などを自分で書く必要がなくなる。

Pre Constructでラベルを初期化する。

なぜ実装例のWidgetを使わず、ラベル付をわざわざ作ったかというと

Widget単体でUIと機能実装を完結させたかった為だ。

※これには副作用があるが、対策も含めて後述する。

少し話は変わるが、

Pluginの実装例に、画面解像度等の各種設定を行う

UINavOptionsMenuというものがある。

私は画面解像度の調整を行うWidgetを作ろうと思い、

上記の実装例から該当の処理を見るとこうなっていた。

ごっついのう!

オプションボックスで選択する制御対象の処理を

全て親となるWidgetで実装している。

これは間違いなく正解の形の一つだが、

今回はもっと小さな実装にしたかったので、

調整項目ごとにWidgetを定義してしまう事にした。

例:画面解像度ボックス

上記のラベル付きオプションボックスをParent ClassにしたWidgetを作成する。

https://lh3.googleusercontent.com/pw/ACtC-3da6PIaLqYJWAQQifcmrg9PKyhtzMsNc9bH2VxokzKbcridx53wZGxPjajlwnSLT7UaD8GbmCwG-dRJS5HFMeB3P91qrZ86n-MJvICAMTjwD_9JaYKragplc2lqhdzcPdSJ2YdEaNqtqafLpWEhK8lw=w261-h60-no?authuser=0

Pre Constructイベントで共通の初期化を行っておき…

Init List関数内で、自分の担当するOption項目の初期化を行う。

項目を切り替えた時に、変更を即反映する。

変数Option IndexはUINav Option Boxで定義されているので、

右クリック→Get Option Indexで取得できる。

GameUserSettingsなので、ファイルへの保存は勝手に行われるから楽ちんちんである。

例:ウィンドウモードボックス

画面解像度ボックスと同様にWidgetを作成。

初期化処理を記述し…

項目切り替え時に変更反映。

メニュー

自作のWidgetを配置するMenu。

Parent ClassはUINav Widgetになる。

PluginのOption Menuオプションメニュー実装例に倣い、

水平のカテゴリー選択メニューと

垂直のカテゴリー別項目に分けてレイアウトし、

WidgetSwitcherでカテゴリを切り替える実装にした。

初期化もチュートリアル通りで特に変わった事はしていないが、

カテゴリ選択Gridとカテゴリ内項目GridのEdge Navigation切り替えは

Event化して整理している。

「適用」を押して前のメニューに戻るイベントの実装では、

On Selectイベントは使わず、Event Dispatcherで処理している。

これはUI Navigationの使い方的には正しくないかもしれないが、

項目の追加や入れ替えに強いという利点がある。

部品化したオプションボックスの整列

実は、ここに作成したオプションボックスなどを素直にVertical Boxに入れると

下記のような表示になる。

揃えたい…!

そこで、左隣にVertical Boxを追加し、

Pre Construct時にラベル部分だけそっちに引っ越すという荒業を用いた。

この強引な手法は、

「マウスカーソルをラベルに当ててもFocusされなくなる」

という欠点を持つ。

ラベル部分がNavButtonの配下ではなくなる為だ。

だが、今回はパッド又はキーボード操作のゲームなので気にしない事にした。

マウス操作の場合でも、ボタンやテキストは正常にFocusするのでそこまで困らない気はする。

Tips

操作封印

一度決定ボタンが押されたら、いったん操作を封印したい場合がある。

例えば、ゲームスタートを押した時。

押されたスタートボタンは、押されたことを示すために明滅するし

画面全体はゲームに写る為にフェードアウトし始める。

ここで入力受付を停止しない場合、

フェードアウト中に再度ゲーム開始ボタンを押すとか、

別の項目を選択するなど、想定外の操作をされてしまう。

これは、UINav Widgetから見えるUINav PC変数の

Set Allow系関数で制御ができる。

下記画像は、オプションに入る前の

ルートメニューWidgetのOn Selectの実装である。

決定と同時に操作封印して、想定外の動作を防ぐ。

オプションに入る以外はタイトル画面から離脱するので、封印しっぱなしである。

直前に開いていたWidgetを参照する

オプションから戻ってきたときに

ルートメニューの登場アニメを変えたいなと思った。

これも、UINav Widgetから見える

Returned from Widget変数で取得できちゃうようだ。

便利!

ただ、Pre Construct段階なら見えるが

Construct時にはもうnull初期化されているようだ。

注意点

要素が何もないGridを作ろうとするとCrashするなど、

例外系の処理はまだ手が回っていない部分がある様だ。

用法外の使用は自己責任で行おう。

言い換えれば、攻めた実装をする場合はVisual Studio等

Plugin内変数のDebugができる環境を用意した方が良い。

感想

GridのルールやUINav Componentでやれる事などを覚えるまで若干の時間はかかるが、

覚えてしまえば非常に便利なPluginと言える。

また、この記事で述べてきた通り

自分用の拡張もしやすいように思う。

実装についても、

自分で実装してもこうしただろうなーという部分もあるし

割り切ったなーという部分もあるしで、

どちらにせよ時短&参考になる。

オススメです!

以上