みつまめ杏仁

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

ボスゲージを作ってみる

RPGとかアクションゲームのボス戦なんかで、ボスキャラの体力がものすご~くたくさんあるのを表現したゲージがありますが、そのひとつ作ってみました。

f:id:hiyokosabrey:20180401224309j:plain

参考にしたのは、大人気モバイルゲームタイトルのFGOです。

普通は1本のゲージが何本もあるかのように見せるタイプが多いです。

例えば1本分がHP1500だとしてその4倍のHP6000をボスが持つ場合、単純に4本分削ることになります。その場合ゲージの色分けで表現すれば十分伝わると思うのですが、

f:id:hiyokosabrey:20180401231231p:plain

FGOは少し違いました。

長さは同じでも1本分にあたるHPの量が違うのです。それはゲージに添えられている数字が説明しています。また、ゲージの下にある◆アイコンがゲージのカラーと連動しています。この◆はいったい何を説明しているのか最初分かりませんでした。

単にゲージの本数を表しているだけでこんなアイコン置くかな・・・、と思いながら攻略サイトを眺めていると、どうやら、ボスキャラたちはゲージのカラー(段階)によって攻撃パターンを変えてくる仕様になっている様子。そういえばHP量を表す数字も、毎回カラーごとに一旦 0 になってから新しく仕切り直しています。ラスボスとかでよく見かけるやつです。HPがある程度減ったら形態が変わってHPが再充填されたりする。その段階を◆のアイコンで分かりやすくしてるようです。

いろいろ納得したところで、UE4で作ってみたのを紹介します。

 

色分けはマテリアルで

マテリアルでゲージを作るときは、テクスチャを使ったUVスクロールか、LinearGradientとValueStepコンビの2パターンを良く使います。今回は後者で。

f:id:hiyokosabrey:20180402003418p:plain

左の Valueと書かれた Scalar Parameter Valueノードの初期値は 1.0 にしておきます。

 

質感を出すためにテクスチャを追加します

f:id:hiyokosabrey:20180402003039p:plain 4x40 px のGrayScale

Addノードを使って間に割り込ませます。

f:id:hiyokosabrey:20180402003833p:plain

ブループリントからいじるためのパラメータ用のノードが3つあります。

長さを変化させるのが ScalarParameter です。

f:id:hiyokosabrey:20180402004237p:plain

この変数を 0.0 ~ 1.0 に変化させることになります。

f:id:hiyokosabrey:20180402005017p:plain

今回2本分のゲージをマテリアルで切り替えるようにした理由は、登場や退場演出などで、アルファフェードしたときに重なりを見せなくするためです。

マテリアルは完成。これをUMGに仕込んでいきます。

 

◆用のWdget

ゲージ下のアイコンを別Widgetで作ろうか悩んでみたけど、結局ラクするために用意することにします。

まずUMGのキャンバスに3つのImageパーツを重ねます。

f:id:hiyokosabrey:20180402215453p:plain

 

f:id:hiyokosabrey:20180402215933p:plain

真ん中のパーツには作っておいたマテリアルをセットします。このパーツにブループリントから色のパラメータを渡して着色します。

 

次に消滅アニメーションを用意します。

f:id:hiyokosabrey:20180402220450g:plain

ヒビが入って飛び散る動きをさせたかったのですが説明が長くなるので別に機会にします。ひとまず白くなって消えるだけですが、これはエフェクト用のパーツをアルファ値のフェードで登場させ最後のフレームで下敷きを残して消しています。

VANISHというアニメーション名にしておきます。

 

次にブループリントを編集します。

カラーを受け取る関数を用意します。

f:id:hiyokosabrey:20180402224457p:plain青いピン(引数:DetailsタブのInputsの項目で追加)はLinearColor型です。

f:id:hiyokosabrey:20180402224839p:plain

関数が用意できたら、EventGraphに戻って、カスタムイベントを一つ用意します。

これは消滅時のアニメーションを再生するためのものです。

f:id:hiyokosabrey:20180402225038p:plain

以上で◆アイコン用のWidgetは完成です。

 

 

HPゲージ本体

ゲージ本体のWidgetを作っていきます。

キャンバスはこんな感じ。

f:id:hiyokosabrey:20180402225837p:plain

ゲージ本体のパーツは、マテリアルをセットしておきます。

f:id:hiyokosabrey:20180402230251p:plain

マテリアルでゲージを変化させるので、このゲージの長さは適当でOK。

 

左下の Horizontal Box は Panelカテゴリのパーツで、ブループリントから子供Widgetを追加すると自動で水平方向に並べてくれる便利なやつです。サイズが小さいのは中身に合わせて可変する設定 Size to Content が 有効(True) になっているからです。この時点では中身はカラです。

f:id:hiyokosabrey:20180402230657p:plain

下敷き以外のパーツは、 必ず Is Variable にチェックを付けておきます。

f:id:hiyokosabrey:20180402231201p:plain

これでブループリントからいじることができます。

UMGは以上です。

 

ではブループリントを編集していきます。

まずは Event Pre Construction イベントから。

f:id:hiyokosabrey:20180402231424p:plain

このイベントはコンパイルした時点で処理される特殊なイベントです。

変数の初期値をセットしたりするのに向いています。

 HPの段階は配列変数で管理したいので、段階ごとのカラーをLinearColor型の配列変数で用意します。マテリアルを頻繁にいじることになるので、ここで Dynamic Mterial Instance 作って変数化しておきます。Get Dynamic MaterialノードのReturn Value ピンの上で右クリックして Promote to Variable を選択するとラクちんです。

 普段 マテリアルは Static(静的)なものとして扱われます。ブループリントからいじりたい場合はDynamic(動的)なものとして扱います。この辺はお約束として覚えておけばいいと思います。

 

つぎに関数を5つほど用意します。

 

まず一つ目 簡単なとこから。

showVital

f:id:hiyokosabrey:20180402232623p:plain

引数でもらったInt型の値を、UMGのテキストブロックに流し込みます。

 

2つ目

setVitalColors

f:id:hiyokosabrey:20180402232809p:plain

 ゲージのマテリアルにカラーを渡す関数です。

 

ここで、段階ごとのHPを配列で受け取るための変数を用意します。

f:id:hiyokosabrey:20180402233130p:plain

用意できたら3つ目の関数

setVitalValue

f:id:hiyokosabrey:20180402233348p:plain

今現在のHPを、その段階に設定されているHP(配列に格納)で割ると、比率が出ます。それをマテリアルに渡すとゲージが変化します。今回ゲージを右から左に向かって減らしたいので、1.0から引き算しています。

 

ここで、Int型の変数を2つ新しく追加します。名前は Vital と Level にしました。

ボスのHPを保持するのと、段階を保持する変数です。配列にはしません。

 

この時点で 変数リストはこのようになってます。

f:id:hiyokosabrey:20180402234335p:plain

上の方のUMGパーツたちは、Is Variable にチェックをつけるとここに並びます。

一番下の Boss~ はこの後説明します。

 

4つ目

initGauge

f:id:hiyokosabrey:20180402233803p:plain

先に用意した関数を並べます。引数で指定した段階のHPでグラフをセットします。

開始時と段階が進んだ時にこの関数が呼ばれます。

 

5つ目の関数をに行く前にマクロを作ります。

ブログで説明するには長くなるので、マクロにまとめました。

initSubVitalIcon

f:id:hiyokosabrey:20180402235623p:plain

 受け取った配列の数から1ひいた分だけ ◆用Widgetを生成して並べます。後でいじるので、生まれたばかりのWidgetを配列の形で格納(空っぽの配列にAdd)しています。Create Widget ノード の Return Value ピンの上で右クリックして Promote to Variable を選択した後、いったんそのSetノードをグラフから削除します。そしてDetailsタブの方で配列化します。

f:id:hiyokosabrey:20180403000208p:plain

 

いよいよ5つめの関数

setupBossVital

f:id:hiyokosabrey:20180403000636p:plain

この関数が外のブループリントから、ボスのHPを配列で値をもらいます。

 

最後にカスタムイベントを作ります。

このイベントでダメージ分を受け取ってゲージを減らします。

updateVitalValue

f:id:hiyokosabrey:20180403001330p:plain

ダメージの値を受け取って、現在のVitalから引き算します。それを再び変数にセットして、判定を取ります。0以下、ということはマイナスになったかどうかを確認します。

 

いいえ(0以下ではない)だった場合

f:id:hiyokosabrey:20180403001831p:plain

そのままゲージの見た目を更新

 

はい(0以下)だった場合

f:id:hiyokosabrey:20180403002037p:plain

 段階を一つ進めます。こここでも段階がまだあるかどうか判定してから次に進みます。

下段はもう段階がないので、事実上ボスは倒したことになります。

 

以上で完成です。

 

さっそくレベルブループリントからテストしてみましょう。

f:id:hiyokosabrey:20180403002655p:plain

とりあえず段階は4にしてみます。

この状態では、ゲージが減らないので、シミュレーション用のInputイベントを使います。

UE4はキー入力のイベントを扱うノードが充実してるので好きです。

f:id:hiyokosabrey:20180403003013p:plain

 スペースキーを押すたびに、500~5000のランダムな値をゲージWidgetの関数に送り込んでいます。ダメージとして計算してくれるはずです。

 

f:id:hiyokosabrey:20180403004335j:plain

f:id:hiyokosabrey:20180403004347j:plain

無事動いています。

f:id:hiyokosabrey:20180403004414j:plain

ちゃんと下の◆も連動しています。

f:id:hiyokosabrey:20180403004446j:plain

カラーを配列にしているのですが、0番目を透明にしている訳は↑これです。

f:id:hiyokosabrey:20180403004930p:plain

動作がかなりそれっぽくなったと思うのですがいかがでしょうか。

 

今回はFGOの敵HPゲージを目コピしてみましたが、なかなか楽しかったので、また気が向いたら既存のタイトルを再現してみます。

 

ではでは今回はこの辺で

ステキなボスゲージライフを!

 

 

横方向のアイテム選択UI 《おまけのオマケ》

4.19がリリースされましたね。楽しみですがまだ落としてないので、引き続き 4.18.3で書いてます。前回のおまけに続いてさらにオマケを作ってみました。今回は ロックとアンロックの状態切り替えを組み込んでます。

f:id:hiyokosabrey:20180316234046p:plain

 ロック状態であることを分かりやすくすることで、解除したくなる心をくすぐる仕掛けです。完全に隠さないことでゲームのプレイ寿命を延ばす効果があります。この仕組みだと、あらかじめロックされているのを見せているので、解除されたことをことさら明示する必要がないのも特徴です。

 ネタバレなので表示したくないとか、アップデートなんかで後から物理的に追加される場合もあるので、隠さないといけない場面も多々あります。

 完全に隠す場合、何が増えたか気づきにくいので、New 的な表示が必要になります。さらにNew的な表示はその表示を消すタイミングと、セーブデータに反映する仕組みも必要になるので、比較的制作コストと不具合のリスクが高くなります。

 今回は隠さずに表示しておいて選択できないタイプで進めます。

 

まずは、鍵アイコンを用意します。

f:id:hiyokosabrey:20180316235447p:plain

この手前の面にカギ穴のあるタイプの錠って、ほとんど見かけないんだけど、ここにないとバッグに見えてストアのアイコンと間違われるから仕方ないんだよな、たぶん。

 

イコン画像ができたところでアイテムパーツのWidgetから編集していきます。

 

WD_Item

f:id:hiyokosabrey:20180316235708p:plain

LOCKされている場合は暗くすることにします。

最初に呼ばれる関数 setupItem にBoolean型の引数をひとつ追加します。

それをSelectノードを使って2色を振り分けます。

f:id:hiyokosabrey:20180317000022p:plain

このWidgetは以上です。

次はフォーカス表示用のWidgetです。

 

WD_ItemFocus

f:id:hiyokosabrey:20180317000228p:plain

キャンバスに鍵アイコン用のImageを追加します。

f:id:hiyokosabrey:20180317000454p:plain

ZOrderは、アイテム画像とタッチおよびクリック検出用のボタンとの間にします。

 

ロックされているアイテムは暗い状態のままアニメーションさせつつ、鍵アイコンの表示をアニメーションの中で切り替えます。

ちょっと楽したいのでフォーカス時のアニメーションを複製して、ロック状態専用のアニメーションを用意します。

f:id:hiyokosabrey:20180317001002g:plain

ブラーパネルを追加しても面白そうですがキャンバスはこの辺にしておきます。

 

次にGraphの編集に移ります。

鍵アイコンを初めからチラ見せする訳にはいかないので、しっかり非表示にしておきます。

f:id:hiyokosabrey:20180317001113p:plain

 

新しくBoolean型の変数を用意します。

そしてフォーカス演出のイベントにBoolean型のピンを追加して、その値を用意した変数で受け取り(セットのかたち)します。

f:id:hiyokosabrey:20180317002354p:plain

それをブランチノードの分岐で利用します。下図は続きです。

f:id:hiyokosabrey:20180317002818p:plain

このイベントの全体は以下のようになります。

f:id:hiyokosabrey:20180331195747p:plain

 

 

で、さらにタップかクリックしたときの決定演出イベントでも分岐を入れます。

f:id:hiyokosabrey:20180317003041p:plain

ロックされていれば、タップしても無視するようになります。

以上でフォーカス表示用のWidgetは編集完了です。

 

最後に親のWidgetです。

 

WD_ItemList

f:id:hiyokosabrey:20180317003346p:plain

 

ロックとアンロックのテーブルをBoolean型の配列で用意します。

f:id:hiyokosabrey:20180317003857p:plain

このテーブルの内容を、アイテムを並べる際に渡します。

f:id:hiyokosabrey:20180317004232p:plain

もう一か所同じように、テクスチャとブール値を渡すところがあるので、このGETノード2個をマクロにしてしまいましょう。下のように4つのノードをハイライトして、

f:id:hiyokosabrey:20180317004605p:plain

右クリックすると、コンテキストメニューが出るので、Collapse to Macro を選びます。

f:id:hiyokosabrey:20180317004705p:plain

するとこうなります。↓

f:id:hiyokosabrey:20180317004813p:plain

いろいろ名前が分かりにくいのと、左側のピンはどちらも同じ値でOKなので、1本にまとめたいので、ダブルクリックして編集しましょう。中身はこんな感じにします↓

f:id:hiyokosabrey:20180331202334p:plain

マクロの編集が終わって戻ってくると、なにやら不穏なことになっている様子。

f:id:hiyokosabrey:20180317005235p:plain

Inputのピンを強制的に1つ減らしたせいです。

左の赤いラインを消して(Altキー押しながらラインを左クリック)あげると正常になります。

 

さっそくこのマクロをSetFocusItem の関数でも使います。

f:id:hiyokosabrey:20180317005918p:plain

↑Before   ↓After

f:id:hiyokosabrey:20180317005636p:plain

編集は以上です。

 

動作を確認してみましょう。

f:id:hiyokosabrey:20180317010937g:plain

今回はロック・アンロックの表現ですが、所持金と販売額を比較して最初のセットアップ関数でフラグ(Boolean)テーブルを作れば、ショップの表現に転用できそうです。

アイテム名に《未購入》とかの文字列をくっつけたり、ロック状態のアイテムを決定すると、ストアに飛ばすのもいいかも、いや良くないか・・・ダイアログだせば・・・などと考えてみたり。

 

 UIの開発って、結構ロジカルで地味だと思うんですが、こういったちょっとした振る舞いで、ユーザーの心象をある程度操作できるので、難しいし奥が深くて楽しいですよね。

 左右のボタンを押したときのスクロール方向を逆にしてみたりするとまた違う印象で楽しめます。(なんか違和感!という気づきがあったりします)あのお風呂の湯船に足を入れるのはどちらの足か? みたいな無意識に操作してて当たり前になってることを改めて見直すと、新しいUIの発見があるかもです。

 と、なんだかまじめな話になってしまいましたが、今回はこの辺で。

 

ではでは

ステキなロック表示ライフを!

 

 

 

横方向のアイテム選択UI 《おまけ》

 昨日家に帰ってから寝落ちしつつ作ったので、なんか文体がおかしい気もしますが無事 喜んでいただけて良かったです。モノ自体はだいたい1時間ほどでできました。アイコンの素材探しと、記事を書くのに時間がかかりましたが、UE4でのUMGユーザーが増えることを願ってこのブログを始めたので楽しく書かせてもらいました。しかもネタもできてうれしいです。

f:id:hiyokosabrey:20180316030052p:plain

 さてさて、決定したときの処理が無かったので、軽いやつを作ってみました。まずはフォーカス表示用のWidgetから。

 

WD_ItemFocus

f:id:hiyokosabrey:20180316023907p:plain

ちょっとトリッキーなつくりかもしれないですが、Buttonパーツを使います。

これをキャンバスの子供に追加します。ZOrderはアイテムの画像より手前で。

f:id:hiyokosabrey:20180315212243p:plain

これを透明にします。

f:id:hiyokosabrey:20180315212512p:plain

HiddenやCollapseなどの非表示設定にしてしまうと、キャンバスに存在しないことになって、タッチやクリックを検出しなくなるからです。

Buttonをこのように上からかぶせない方法もありますが、ちょっと手軽じゃないので今回は簡単なやつでいきます。

前回の記事に書いた方法で、onPressedイベントを使います。

f:id:hiyokosabrey:20180315213938p:plain

そして、タッチまたはクリックしたことを通知するためにイベントディスパッチャーを使います。

エディタウィンドウの左にあるMyBlueprint タブの中にあります。

f:id:hiyokosabrey:20180315214528p:plain

通知するだけなので適当に名前を付ければOKです。

今回タッチまたはクリックしたときのリアクションに短いアニメーションも作りました。

f:id:hiyokosabrey:20180315215115g:plain

これを onPressedのイベントにつなぎます。

f:id:hiyokosabrey:20180315215446p:plain

 

これで完成。

つぎはこの通知を受け取るWidgetを編集します。

 

 

WD_ItemList

f:id:hiyokosabrey:20180316023855p:plain

ForloopノードのCompletedピンからの続きに、バインドノードをつなぎます。

f:id:hiyokosabrey:20180315215657p:plain

フォーカス表示用のWidgetはすでにキャンバスに置いてあるので、Getの形でGraphに置いたら、「Bind」で検索するとイベントディスパッチャーを追加したときの名前が見つかります。そのバインドノードには Eventピンがあるので、ここにカスタムイベントをつなぎます。

f:id:hiyokosabrey:20180315223303p:plain

これで、中央のアイテムをタップかクリックすると、アイテム名がデバッグ表示されるようになります。今回はサンプルなのでここまでにしていますが、買ったり使用したりといった処理がこのあと続くと思います。さらに上位のWidgetに通知することもできます。

 UE4で UIを作る場合、複数のWidgetをパーツとして組んでいくので、このブループリント間で連絡しあう仕組みがとても活躍します。普段親から子に対しては、親が一方的に子に指示をして子はそれに応えることしかできません。ところがイベントディスパッチャーを使うと、「バインド」で親が子にケータイを持たせて、子から自身のタイミングで親へ連絡させることができます。

 

 とりあえず軽いやつですが汎用的なつくりですので、後はアレンジとか応用になるかなと思ってみたり。

 

 スワイプまたはドラッグでのスクロールについては、そういった操作に対応できるノードが用意されているので作れそうですが、今回の構造に追加するのはちょっと難しいです。最初から設計を変えて作り直した方がよさそうですね。

 

 ではでは今回はこの辺で

ステキなEventDispatcherライフを!

 

 

 

 

横方向のアイテム選択UI

今回はコメントを頂いたのでその返答として書きます。コメントいただけると嬉しいですね。続けてきた甲斐があるってものです。

で、作ってみたのはこれ。

f:id:hiyokosabrey:20180314225501p:plain

いくつかのアイテムを左右にスクロールさせて選択するメニューUIです。

今回アイテムの絵素材として FLAT ICON DESIGNさんとこのを使わせていただきました。

3つのWidgetアセットで構成します。

まず、選択用に並べるパーツとしての Widgetとフォーカス状態を表すWidget

f:id:hiyokosabrey:20180314231253p:plain

そして、これらをまとめるWidgetです。(※名前は適当です)

ではさっそく、並べる方から用意していきます。

 

WD_Item

UMGのキャンバスはシンプルです。

f:id:hiyokosabrey:20180314231737p:plain

並べた時にくっつきすぎないようにCanvasPanel (Sizeは120x120)を置いて、中にImage を子供にして配置します。

f:id:hiyokosabrey:20180314232130p:plain

 

つぎにGraphを編集します。

 

テクスチャを受け取る関数を用意します。

f:id:hiyokosabrey:20180314232410p:plain

次にカスタムイベントを用意します。

f:id:hiyokosabrey:20180314232618p:plain

これはフォーカスされているときと、されていない時で表示/非表示を切り替えるためのイベントです。カスタムイベント側の緑のピンは、右のSet Visibilityノードにある 緑のピンからドラッグ&ドロップすると、簡単に追加できて便利です。

 

f:id:hiyokosabrey:20180314233104p:plain

以上で並べるためのパーツは完成。

次は、フォーカスされたアイテム用のWidgetを作ります。

 

WD_ItemFocus

これもキャンバスはシンプルな構成で十分です。

f:id:hiyokosabrey:20180314233537p:plain

ただ大きいだけだと面白くないのでアニメーションを仕込んでみます。

f:id:hiyokosabrey:20180314234228g:plain

キャンバスはこの辺で、次にGraphを編集します。

 

アイテムを切り替える際、見えない状態から始めないとタネがバレるので、カラーを透明にしておきます。

f:id:hiyokosabrey:20180314234431p:plain

この Event Pre Construct につなぐと、エディット中から適用されるので、Add to Viewport したときのチラ見えを安全に防ぐことができます。

 

次はフォーカスされて表示を更新するカスタムイベントです。

f:id:hiyokosabrey:20180314234909p:plain

フォーカスされるアイテムはプレイヤーの動作に応じて動的に変化するので、このイベントで、テクスチャを受け取ってアニメーションを再生しています。

 

以上でパーツのWidgetは用意できました。

次に、全体をまとめて管理するWidgetです。

 

WD_ItemList

 まずUMGのキャンバスは以下の構成になります。

f:id:hiyokosabrey:20180315001833p:plain

最初からあるCanvasPanelとは別に、新しく置いた CanvasPanel は、HorizontalBox をクリッピングする(CanvasPanel の外側は描画しない)ために用意しました。後述。

ヒエラルキーはこんな状態

f:id:hiyokosabrey:20210828143615p:plain

 

 HorizontalBox の大きさは、Size To Content にチェックをつけて有効にしておきます。

f:id:hiyokosabrey:20210828143915p:plain

この時点で中身が空なので、左上に縮こまってます。

 

 CanvasPanelの大きさは、実際に表示する大きさなので、アイテムWidgetのサイズと表示個数によって調整します。今回アイテムWidget1個のサイズが120x120で、7個が見えている状態にします。さらに両端に半分が見えるようにしたいので、合計8個分として 120 × 8 = 960 の幅で作成します。両端のチラ見せは、並んだアイテムの続きがあることを印象付けるためです。

 

今回アイテム120x120が 8個 並ぶ想定でサイズを決めました。

f:id:hiyokosabrey:20180315003452p:plain

 

 また、少し前のVerから、キャンバスの外側にも子供を表示する仕様がデフォルトになったので、キャンバスパネルの設定を変更する必要があります。

f:id:hiyokosabrey:20210828143934p:plain

CanvasPanelを選んだ状態でのDetailsタブにClippingの項目があるので、これを探して変更しておきます。 Inherit → Clip to Boundsf:id:hiyokosabrey:20180315003936p:plain

 

最後に、フォーカス表示用のWidgetを、User Created の中から探してキャンバスに追加します。ZOrderの値を大きくして、手前に重なるようにします。

f:id:hiyokosabrey:20180315004834p:plain

これは入れ子にはしません。

 

 

つぎに Graphの編集に移ります。

 

アイテムを半分チラ見せしたいがために、ちょっとだけ表示位置の調整が必要になります。

f:id:hiyokosabrey:20180315011228p:plain

このために、Float型の変数を用意します。

CanvasPanel(CanvasPanelListと命名)のサイズを取得して計算し初期位置を求めます。

f:id:hiyokosabrey:20180315043136p:plain

今回のスタイルのUIは、スクロール方向がキー操作と逆にしているので、アイテムWidgetの表示サイズをマイナスの値で扱うことにします。最初からマイナスにしておくことで計算が一つ減ります。

この辺の事前準備は、必要なパーツも最初からキャンバスに揃っているので、Event Pre Construct で行っています。

 

続いて Integer型の変数を2つ用意します。フォーカス中のIndex番号を保持するためのものと、アイテムを必要個数分生成して追加しつつスクロールの端をチェックするための2つです。

f:id:hiyokosabrey:20180315044247p:plain

まん中の関数は、アイテムの中身をセッティングする関数です。内容は以下。

f:id:hiyokosabrey:20180315045204p:plain

ここはプロジェクトのデータ管理方法によっては違うつくりになると思いますが、この関数で表示するためのアイテムを準備します。

後から追加しやすいことを考えて、テクスチャアトラスは作らず、バラバラで個数分用意しました。

f:id:hiyokosabrey:20180315045851p:plain200x200

それをTexture2D型の配列変数にあらかじめ登録しておきます。

 

大量のテクスチャアセットをインポートする場合に便利なのがこれ↓

f:id:hiyokosabrey:20180315050354p:plain

コンテンツブラウザで、対象の画像アセットを複数選択しておいて右クリックすると選択できます。扱い方はこちらのブログに詳しく紹介されています。

【UE4】Sound Cueのパラメータを一覧して一括変更する方法 - SAT04 CREATIVE SPACE

サウンドアセット用の解説なのでパラメータは違いますが、基本的な操作は同じです。

 

次に、アイテムを並べていきます。 Forloop ノードを使って必要な個数分の処理を回します。

f:id:hiyokosabrey:20180315052035p:plain

Create Widget したあとすぐに WD_Item型の配列変数に追加(Addノード)しています。これは、並べたアイテムを後からIndex番号で扱いたいからです。

HorizontalBoxに子供として追加すると自動的に水平方向(基本的に左から右)に並ぶことになります。

ひととおり並べ終わったら、フォーカス表示用のWdgetにテクスチャを渡すのと、アイテム名の表示を行う関数を用意して、Forloopノード Completeピンにつなぎます。

f:id:hiyokosabrey:20180315053237p:plain

 

次はスクロールの動きを作る関数です。

f:id:hiyokosabrey:20180315054709p:plain

慣れないとややこしそうに見えますが、このブログでもよく登場するやつです。

( 目的地 - 現在地 )×  減速率 を 現在地に足す ことで減速しながら目的地に向かいます。

減速率の 0.25 という値をいろいろいじって加減してみてください。

 

この関数を、Event Tick につなぎます。

f:id:hiyokosabrey:20180315054856p:plain

 

次に、アイテムのフォーカス位置(FocusIndex)を増やしたり減らしたりするイベントを用意します。

f:id:hiyokosabrey:20180315055855p:plain

f:id:hiyokosabrey:20180315055823p:plain

左端のイベントノードは、一つはカスタムイベントですが、もう一つは、ボタンから生成したイベントノードです。作り方は簡単。編集モードをDesigner に切り替えます。

 

キャンバスのButtonパーツを選択した状態でDetailsタブの一番下にEvents という項目があります。この緑色の + ボタンをクリックすると、Graph に出現します。

f:id:hiyokosabrey:20180315060228p:plain

 

このイベントで、FocusIndexの値が更新されたので、見た目に反映する必要があります。最後に関数をつないで完成です。

f:id:hiyokosabrey:20180315055838p:plain

と言いたいところですが、あとひとつ関数を追加します。

f:id:hiyokosabrey:20180315060747p:plain

これはフォーカスを切り替えた際に、非表示にしていたアイテムを戻す関数です。

このイベントの処理を簡単にまとめると、

f:id:hiyokosabrey:20180315061605p:plain

という流れになります。

 

 

さっそくテストしてみましょう。

レベルブループリントから、ビューポートに追加します。

f:id:hiyokosabrey:20180315061857p:plain

これで再生すると動きますが、キーボード操作用のイベントも追加しておきます。

f:id:hiyokosabrey:20180315062108p:plain

 

再生してみます。

f:id:hiyokosabrey:20180315063010g:plain

 GIFなのでブラウザによっては速度がでないかもしれないですが、結構いい感じになったと思うのですがいかがでしょうか?左右の端に行くとループしているので反対側に一気に飛びます。

左右にある灰色の四角はUMGに用意されているもので、グラフィックを設定していないので、見た目はショボいですがちゃんと反応します。

 

今回決定処理はないですが、ひとまずそれっぽい挙動は作れたかと思います。

説明が分かりにくいところとかあればツッコミコメントをお願いします。

 

ではでは

ステキなアイテム選択UIライフを!

 

スピンボックスも作ってみた

 前の記事でインターフェイスを作りましたが、せっかくなのでスピンボックスも作ってみることにしました。

 スライダー同様、ゲームの設定画面とかでよく見かけます。スピンボックスはGUIの1スタイルでMicrosoft Developer Networkのドキュメントに簡単な説明があります → スピンボックス

 

 ▲と▼をクリックするたびに値が1段階変化します。数値を増減させるときに便利なのですが仕組みとしてテキストなどの文字列を入れて使われることもあります。数値のみの場合は明確に区別するために、 Numeric Stepper と呼ぶこともあるようです。

f:id:hiyokosabrey:20180225110925p:plain

 テキストの場合は、序列や段階を意図した言葉選びが重要です。したがって、このUIのメリットは  選択中の状態が分かりやすい ことと、その前後の内容が予測しやすい ことにあります。なので、増減と関連性のない、前後の脈絡のないテキストを選択肢にすると、複数ある選択肢の全体が把握しづらいため一通り送って確認しないと選べないので時間がかかります。

f:id:hiyokosabrey:20180225111352p:plain

ゲームクリア後や実績解除などで、後から選択肢を追加しても画面のレイアウトに影響がないので、開発者にとっては都合のいいUI だったりします。でも途中で内容が増えても気づかないので、Newマークを付けたり、お知らせ表示を入れたりと、開発側としては結局手間がかかることに・・・。用法容量を守り正しく活用したいものです。

 このへんがデメリットとなって使いづらさにつながるので、段階や序列のないテキストを選択肢にする場合はコンボボックスやリストボックスがオススメです。もちろん表示に余裕があれば全部並べて選択させるのがベストです。ゲームのUIってほとんどが選択肢と言っても過言じゃありません。なんらかの選択をユーザーにさせてユーザーの意思を尊重しているかのようにふるまいつつ、都合の悪い選択肢なんて最初から無かったことに・・・うわやめろなにを・・・ゴフゥ・・・中断

 

 

 

 げふげふ(さてさて)、

 今回はスライダーなどと操作方法を統一するために ↑ ↓ キーで項目を選んで、←→キーで内容の切り替えを行うようにします。レイアウトはスライダーと同じように並べるので↓のようになります。

f:id:hiyokosabrey:20180225104855p:plain

新しくWidgetを用意してもいいですが、スライダーWidgetと共通の部分が多いので複製します。

 

 

UMG

f:id:hiyokosabrey:20180225185602p:plain

不要なパーツを消してテキストブロックに置き換えます。

テキストブロックは is Variable にチェックを付けるのを忘れないように。

 

 

Widgetブループリント

必要な変数を用意します。複数の選択肢を扱うので、その個数を保持する integer型の変数と、受け取った選択肢用の Text型の配列変数です。

f:id:hiyokosabrey:20180225190516p:plain

値を受け取る初期設定用の関数 initValue は ↓ のように変更します。

f:id:hiyokosabrey:20180225205556p:plain

 

 値を見た目に反映する関数 updateValue の中身は受け取った配列の中身を取り出すだけなので、 ↓ のようになります。

f:id:hiyokosabrey:20180225204654p:plain

配列のエラーチェックをする場合は IS VALID INDEX ノードが便利です。

f:id:hiyokosabrey:20180225205155p:plain

 

値をアイテムの数だけでループするようにするので、rangeCheck マクロを編集します。

f:id:hiyokosabrey:20180225210010p:plain

 

これでコンパイルしてエラーが出なければ完成。

 

制御用Widget

キャンバスにできたスピンボックスのWidgetを追加します。

f:id:hiyokosabrey:20180225210528p:plain

初期化の関数に追加します。

f:id:hiyokosabrey:20180225210727p:plain

選択肢用のアイテムはここで、Make Arrayノードで渡します。

 

アクティブなWidgetを切り替える関数にも追加します。Switch on Int ノードをAdd pinして割り込ませます。

f:id:hiyokosabrey:20180225210917p:plain

 以上です。メンバーが一つ追加になったのにこの簡単さ。これもインターフェイスのおかげです。

さっそく再生してみましょう。

f:id:hiyokosabrey:20180225212445g:plain

 

これでどんなセッティング画面が来ても対応できそうな気がしてきました。

あと必要そうな処理としては、制御用Widgetに値を返すようにしたり、変更内容をリアルタイムに反映したいときのために イベントディスパッチャーを用意したりすれば完璧な予感。

なんかUIって、表のグラフィックデザインにスポットが当たりがちですが、実際はこういった地味な内部処理が頑張ってたりするんですよね~ とか呟いてみたり。

コンポーネントとして用意されているので、わざわざイチから起こさなくても・・・

という声が聞こえてきそうですが、やっぱり仕組みを知ることで、次の新しいUIが生まれてくる気がするんですよ。

 

今回インターフェイスは使い回したので説明はしてませんが、汎用的なやつが一つあれば結構いろんなUIパーツに適用できるのでおすすめです。

 

というわけで今回はこの辺で。ツッコミとかリクエストとかあればコメントください。

ではでは

ステキなBPインターフェイスライフを!

 

 

 

スライダーUIを並べて操作してみる 《おまけ》

キーリピート処理の説明用にスライダーUIを作ってみたら、なんとなくいい感じになってきたので調子に乗って”初期設定に戻す”機能を追加してブループリント インターフェイスまで扱うとこまできたのですが、もうひとつ「ミュート」の切り替えができるようにして完了にしようと思います。

f:id:hiyokosabrey:20180220225350p:plain

 

前回の記事はこちら

 キーリピート機能をつくってみる - みつまめ杏仁

スライダーUIを並べて操作してみる - みつまめ杏仁 

スライダーUIを並べて操作してみる 《続き》 - みつまめ杏仁

 

アイコン

まずはアイコンの仕込みから

 

テクスチャは簡単な2パターンを用意します。2つの画像に分けてもよかったりしますが、今回はマテリアルで切り替えます。

f:id:hiyokosabrey:20180220225549p:plainSize: 96x96

 

画像をテクスチャとしてインポートしたら、そこから Create Material します。

f:id:hiyokosabrey:20180220230054p:plain

UVスクロールさせるだけのシンプルなマテリアルです。

 

 

Interface

インターフェイスにあとひとつ関数名を追加します。

これは A とか 〇 とかの「決定」ボタンを押したときに呼び出すイベント用です。

f:id:hiyokosabrey:20180221223507p:plain

コンパイルして閉じます。

ここでちょっと注意が必要なのが、インターフェイスを編集して保存すると、そのインターフェイスをセットしているブループリント全てが、再コンパイル対象になってしまうということです。

f:id:hiyokosabrey:20180221224142p:plain

なので、UE4を閉じるときに、普段触っていなかったブループリントが「save する?」

って訊いてきて慌てることがあります。インターフェイスを触るときは、心の準備をしてから触るようにしましょう。エラーが出てるとマズいので、アスタリスクのついたアセットは、面倒ですが一度開いてコンパイルしてから閉じるようにします。

 今回のスライダーのWidgetはそのまま編集をします。

 

 

UMG

まずはスライダーWidgetのキャンバスにアイコンを配置します。

f:id:hiyokosabrey:20180220230852p:plain

Imageパーツを表示したいサイズに調整して、作っておいたマテリアルをセットしてやります。

 

Widgetブループリント

つぎにGraphの編集です。

まず、 ブーリアン型の変数 "isMute" を一つ追加します。

f:id:hiyokosabrey:20180221225227p:plain

 

この変数を使って見た目を切り替える関数 "switchMuteDisp" を用意します。

f:id:hiyokosabrey:20180221225613p:plain

今回 ミュートのON / OFF で変更するのは3パーツ。

f:id:hiyokosabrey:20180221230435p:plain

扱う値が違うので結果的に3種類のSelectノードを使うことになりました。

Selectノードは ブーリアン型の値、 True か False を判定して、あらかじめ決めておいた対応する値を取り出してくれる大変便利なノードです。Brunch ノードで組むこともできますが、白いラインが分岐することを考えると、Selectノードを使う方がスッキリして見えます。

つないでみて気づくのですが、テキストのカラーについては SlateColor と呼ばれる特殊なカラー値なので、LinearColor が使えません。さらに面倒なことにSelectノードの上下にならんだピンの扱いがなぜか逆という・・・

 

さてさて 見た目をチェンジする関数ができたところで、初期設定用の関数に追加した変数を加えます。

f:id:hiyokosabrey:20180221231416p:plain

新しく引数(Inputs)ピンも追加。最後に、できたての見た目チェンジ関数をつなぎます。

 

あとはボタンを押したときに呼ばれるイベント。

f:id:hiyokosabrey:20180221231754p:plain

ブーリアン型の変数 isMute の内容をスイッチングします。スイッチングしたあとは見た目に反映するためにつくった関数をつないでいます。

これでスライダー用のWidgetは完成です。

 

制御用Widget

 スライダーWidgetの 初期設定用の関数に引数を追加したので、ノードが変化しているのが確認できます。

f:id:hiyokosabrey:20180221232348p:plain

 

前回の記事でリセットするイベントを作りましたが、そこにノードを追加します。

f:id:hiyokosabrey:20180221232619p:plain

単純にIndexFocus の値が3 以外なら、onDecide のイベントを呼ぶようにします。

これで、できあがりです。

 

再生して確認してみましょう。

f:id:hiyokosabrey:20180221233313g:plain

うまくいきました。

ただこの操作はユーザーが気づきにくいので、画面の隅にでも操作ガイド的なナビ表示があった方いいでしょうね。マウスクリックを受け付けるなら、おそらく直接スピーカーのアイコンを触るので心配なさそうですが、そうなるとアイコンのデザインも、もう少しボタン感のある見た目にしないといけないですね。

 

ひとまずスライダーUIに関してはここまでにします。

ではでは

ステキなスライダーUIライフを!

スライダーUIを並べて操作してみる 《続き》

前回それなりにサウンド設定ができそうな雰囲気を醸し出すことができました。

そこにリセット用の項目を追加してみます。

f:id:hiyokosabrey:20180218225034p:plain

右端にもオマケでアイコンを追加しています。

 

 前回の記事はこちら。limesode.hatenablog.com

 ↑これをベースにいじっていきます。

 

Blueprint Interface

今回の肝は、タイプの異なるWidgetを並べて操作できるようにする部分になります。そのための準備として、インターフェイスを用意します。

f:id:hiyokosabrey:20180218225616p:plain

とりあえず ”IF_Settings” と名付けました。

f:id:hiyokosabrey:20180218225841p:plain

ダブルクリックして、エディタ右上にある追加ボタンで関数名を4つ追加します。

f:id:hiyokosabrey:20180218230025p:plain

コンパイルして保存したら閉じます。

 

Interfaceを登録

前回作ったスライダーパーツのWidgetを編集します。

エディタをGraphに切り替えて、Class Settings をクリック。

f:id:hiyokosabrey:20180218230621p:plain

Detailsタブに Interface と書かれた項目があるので、そこの Add ボタンを押して、

さきほど用意した IF_Settings をセットします。

f:id:hiyokosabrey:20180218231046p:plain

ここでコンパイルするとエラーがでます。

f:id:hiyokosabrey:20180219094404p:plain

f:id:hiyokosabrey:20180219094801p:plain

同じ名前のカスタムイベントがいるためです。

そこで急いでイベントを入れ替えていきます。

いつものグラフで右クリックしてノードが検索できるやつで探すと出てくるので、つないであったカスタムイベントと入れ替えます。ちょっと見つけにくいけど、Add Event の中にいます。

f:id:hiyokosabrey:20180219093529p:plain

Add Event カテゴリにいるのは、Interfaceで関数に戻り値(Return Value)を設定しなかったのが理由ですが、UE4は戻り値がない関数はイベントとして扱われることがあります。頭に"Event" と付けられていますが、本当の名前には付いていないので名前が被ることになりました。

f:id:hiyokosabrey:20180219095702p:plain

↑この4つのカスタムイベントをいったん削除して付け替えます。 ↓

f:id:hiyokosabrey:20180219095738p:plain

これでコンパイルしてもエラーは出なくなります。

ちなみに、Interfaceで定義した関数はグラフに置けるのは1つだけなので、2つ目を置こうとすると、すでに置いてある場所にフォーカスが移ります。こういった事故を防ぐ仕様がステキですUE4

スライダーの改造をひと段落つけて、新しいWidgetを用意します。

 

テキストだけのWidget

f:id:hiyokosabrey:20180219101029p:plain

キャンバスには、スライダーと同じ大きさとカラーのテキストブロックを一つレイアウトします。

f:id:hiyokosabrey:20180219101225p:plain

is Variable にチェックを付けておきます。

フォーカス切り替えのアニメーションを付けておきます。

f:id:hiyokosabrey:20180219101920g:plain

グラフでスライダー同様にイベントノードにつなぐのですが、先に Interfaceを登録します。

f:id:hiyokosabrey:20180218231046p:plain

コンパイルしてエラーが出ないのを確認したら、Animationの再生ノードをつなぎます。

f:id:hiyokosabrey:20180219102325p:plain

このテキストだけのWidgetも汎用性を高くしたいので、初期設定用の関数を用意しておきます。

f:id:hiyokosabrey:20180219102554p:plain

テキストを受け取って差し替えるだけのシンプルな関数です。

これで完成です。

つぎは前回作った制御用のWidgetを編集します。

 

 

制御用Widget

 作ったテキストだけのWidgetをキャンバスに並べます。

f:id:hiyokosabrey:20180219112246p:plain

 

初期化している関数 を編集します。

まず配列変数周りをなくして、f:id:hiyokosabrey:20180219113427j:plain

テキストだけのWidgetに、ラベルのテキストを渡します。

f:id:hiyokosabrey:20180219112628p:plain

この関数の外にスライダーWidgetの数を保持する変数が待機しているので、そこに今回の項目数を戻り値として渡します。

 配列変数で処理するのをやめたのは、選択項目に別のWidgetが追加になって配列変数が使えなくなったためです。配列変数の型を wd_slider型 から UserWidget型 に変更しても、その配列変数には 1種類の同型のUserWidgetしか格納できませんでした。

2022/7/16 追記>>

あらんさん にご指摘(ブログ下部コメント参照)いただいて調べてみました。

記事を読み返してみて、前回の操作ですでに並べたWd_Slider型のオブジェクトから Promote to variable(変数に昇格) してる箇所があります。それを配列にしてるのでUserWidgetというカテゴリではありますが、VariableTypeが Wd_Slider型の配列になっているので、当然別のWd_TextOnly型が挿さらないわけです。当時の自分にツッコミに行きたい。

というわけで、Promote to variable せずに 新しくVariableTypeが UserWidget型の配列変数をつくるとエラーが出ずに、スルっと追加できます。

← ver4.27のキャプチャ

あらんさん ありがとうございます!

記事を書き直そうかと思ったのですが、差し替える必要のある画像が結構あって、しかも手元にあるUE4系は 4.27しかない状況。4.27でもプロジェクトファイルを開くことができました(この記事執筆時は4.18使用)が、アニメーションの挙動がおかしいのと、微妙にエディタのUIが変更になっているので、改めて UE5 で書き直そうと決意しました。便利なイベントも増えてますし。少し先になりますがなるべく近いうちにUE5版を公開します。

この記事を見つけて試していただいているのに失敗につき合っていただくのは心苦しいのですが、修正範囲が大きいのものあり、動かないわけではないのでこの記事はこのままにします。

<<

f:id:hiyokosabrey:20180219114844p:plain

そこで、前回は wd_slider型のWidgetしかなかったので、配列変数に格納できてそこから数を調べていましたが、今回は直接数を数えて返しています。

f:id:hiyokosabrey:20180219115439p:plain

ちょっと改造の手間を省こうとしてマジックナンバーで対応していますが、

プログラマに渋い顔をされてしまう場合は、親になっているキャンバスやその他パネルで余計なパーツが入らないようにしておけば、下のようなやり方もオススメです。

f:id:hiyokosabrey:20180219115856p:plain

 

ゲームに限らないと思いますが、UIを作るうえでのあるあるのひとつに、あとから項目の数が変更になるのが挙げられるとおもいます。すべてのノードをいつまでも把握しておくのは難しいので、あらかじめヒューマンエラーを起こさないように自動化しておくのはできるだけやっておいた方がいいです。

 

つぎに新しく、UserWidget型の変数をひとつ追加します。

f:id:hiyokosabrey:20180219121226p:plain

前回作った関数 "changeActiveWidget" を大改造します。

f:id:hiyokosabrey:20180219121620j:plain

↑これを ↓このようにします。

f:id:hiyokosabrey:20180219122241p:plain

ActiveWidgetという器(UserWidget型の変数)に、適宜該当するWidgetを入れていきます。

右端のフォーカスするイベントの呼び出しは、Interfaceで定義した関数にしないといけないので、検索して 作ったInterfaceカテゴリ探します。

f:id:hiyokosabrey:20180219122231p:plain

 

これが Interface の持つステキな仕様です。

なかなかピンとこないかもしれないですが、ActiveWidget に何か適当なWidgetが入っている状態だと仮定して、呼び出すための関数ノードをつなぐことができるのです。

普段、関数を呼び出す際には、呼びたい関数を持っていないとつなぐことができませんが、Interface 経由だと、関数を持っていなくても問題にならないのです。

 

あとは、wd_Slider型の ActiveSlider変数でつないでいるところを、入れ替えていきます。

f:id:hiyokosabrey:20180219173330p:plain

f:id:hiyokosabrey:20180219173408p:plain

後はここ↓

f:id:hiyokosabrey:20180219173605p:plain

 入れ替えてコンパイルに問題なければ完成です。

お役御免になった変数を削除します。

f:id:hiyokosabrey:20180219174506p:plain

確認してみましょう。

f:id:hiyokosabrey:20180219175121g:plain

フォーカスがいい感じに切り替われば成功です。

 

仕上げに、リセットのイベントを追加します。

f:id:hiyokosabrey:20180219180239p:plain

フォーカス用Index番号が 3 の時だけ受け付けるようにします。ちょっと雑ですが初期設定の関数をそのままつないで初期化として使ってます。

 

完全に初期化するか、変更前に戻すかは、決めておく必要がありますが、丁寧に作るならリセット用の関数を用意しておくと後から融通を効かせられます。スライダーWidgetの方にも指定した値に変更する関数があった方が便利です。

 

Index番号で判定する方法については、あとから項目の数が変わったり順番が入れ替わると、きちんと値を変えてやる必要があります。対策の方法はいくつかあると思いますが、今回はこれで。

 

レベルブループリント

リセットのイベントを呼ぶために、Inputノードを追加します。

f:id:hiyokosabrey:20180219181601p:plain

 

動かしてみます。

f:id:hiyokosabrey:20180219182011g:plain

いい感じになってきました。

 

いろんな種類のWidgetパーツを、InterfaceUserWidget型の変数 を使って、汎用的に処理する方法を紹介してみました。

 

長くなったので今回はこの辺にします。

ではでは ステキな設定初期化ライフを!