3人称視点のアクションRPGとかで、フィールドに落ちている何かを拾うと、ログ表示のように画面端に表示されるあれです。
原神をプレイしてて作ってみようと思い立ったUI表示ですが目コピーではないです。
試そうと思ったきっかけは、
- VerticalBoxに追加した UserWidgetが、自身を Remove from Parent したらどうなるのか?
- ガシガシ追加しまくっても、一定時間経過で勝手に消えてくれるのであれば、追加する側が管理しなくてもいいのでは?
という安易な推測によるものでした。
で実際にやってみた作り方をメモメモ。
Widgetを2つ使います。
まず最初に作るのは、表示する子要素であるWidgetから。
UMGのキャンバスには、まとめてアニメーションさせるための CanvasPanel を追加して、あとはその子供として Image(下敷き用)、Image(アイコン用)、TextBlock(アイテム名など)を配置。
↑ Image_Cover は登場時に白くフラッシュさせるエフェクト用です。
最初から配置されている CanvasPanel は、Canvas Panel Slot を持っていなくてサイズを使ったアニメーションができないので放置。
ここでポイントが2つ。
1つは、余白を作っておくことです。
画面に見せたいパーツ(中身)の大きさより、CanvasPanelを少しだけ大きくします。
これが並んだ時のスキマになります。
VerticalBox に追加する際に Padding で調整すると、Paddingの余白はサイズのアニメーションに含まれないため、タイミングによってはかカクっとなるのが見えてしまいます。
← CanvasPanelに余白
← Paddingで余白
アニメーションは、 Open(出現用) と Close(退出用) の2つ。
Open
Close
もうひとつのポイントはここ。
なるべくSizeのアニメーションは最後までとっておきます。
先に Scale と Opacity で見えなくしてから、Sizeのアニメーションをさせるようにすると、リストに追加があったときに見やすくできます。
アニメーションで動きをつけるのは、気づきやすさ(視認性)を上げるうえで有利ですが、静止しないと読みにくい(可読性が下がる)ので、調整は大事です。
UIを試行錯誤しながら作っているこの状況で、気を付けたいのがこの視認性と可読性のバランスです。
テスト用の文字列やアイコン情報を表示しても、内容については仮のものなので、無意識に表示内容をスルーしています。動きや雰囲気に注意が向いている分、そこさえ良ければ、もう出来た感じがしてしまうという罠です。実装後の確認とチューニングはしっかり行いたいものです。
あと、細かいことですが、出現と退出のアニメーションを別々で作っているのは理由があります。
適切な表示時間を、ブループリントでDelay ノードで調整したいからです。
いい感じの表示時間が確定さえすれば、後でタイムラインを一つにできます。
また、表示時間の調整を行う際に、自分以外の方に説明するのが簡単です。
「なんか短くない? 何秒?」
「(Delayの値)1.25秒です」
「2秒にしてみたらどんな感じ?」
「ちょっと待ってくださいね」
てな具合にやり取りができます。
というわけでキャンバスはこのくらいにして、続いてWidgetブループリントを編集。
Event Construct
右下のノード Remove from Parent に Self を指定しているので、自分自身が消滅します。
再生するアニメーションが 2つあるので
上の例では、アニメーション終了検知のイベント は使用しないケース、
下の例は使用するケース。
いくつかの変数をパラメータとして受け取るようにしています。
Expose on Spawn を有効にしているので、この Event Construct が実行される時にはすでにパラメータを受け取っているという段取りです。
最終的に Structure にしたほうがよさそうな気はします。
表示のためのセットアップは、ブループリントのスクショがコンパクトになるようにマクロにしています。
マクロの外に接続するようにしているのは、自分以外の方、もしくは未来の自分がブループリントを見た時に、少しでも何をしているか、何をしようとしているかを解りやすくするための気配りみたいなものです。
で、マクロの中身はこんな感じです。
FormatTextノード便利ですよね。
これで表示する子のWidgetは完成です。
ここからは、リストを並べるためのWidgetを作っていきます。
UMGのキャンバスには、VerticalBox が一つ。
次にWidgetブループリント
簡単なテストということで、変化を楽しむためのカラーを配列に仕込んでいます。
セットしている配列変数は、LinearColor型です。
カスタムイベントを用意します。
CreateWidgetノードに、先に作ったリスト用のWidgetを Class としてセット。
変数の Expose on Spawn を有効にすると、この CreateWidgetノード経由で初期値を渡すことができます。
これで出来上がりです。
あとは適当なレベルを作って表示テスト。
Inputノードで、スペースキーを押すと、カスタムイベントを呼び出す。
Twitterに動画を上げてるので、動きのイメージはこちらから ↓
アイテム取得なんかの時にポップするミニリスト表示を試してみたら、思いのほかサクッとできた。CreateWidgetを使わない方法だとちょっと大変そう。#UE4 #ue4UMG #ue4Study pic.twitter.com/lebFOhauvM
— みつまめ杏仁 (@MMAn_nin) 2021年1月2日
テキストの表示が TextBlock のままですが、動きは同じになります。
一応検証用に、VerticalBoxの子要素をカウントしてみました。
キャンバスに TextBlock を一つ追加して、EventTickで監視した数を常時表示します。
Get Children Countノードを使って調べます。
Remove from Parent で消滅するタイミングでカウントが減ります。
いい感じに動作しているようです。
ガシガシ呼び出しても、勝手に消えていくんで管理する手間が省けていいなぁ、と思いたいけど、実際には表示数に制限が必要だし、制限を越えた分はプールしておいて、空きができたら、プールが空になるまで逐次追加し続けたりしないといけない。
とはいえ、最初の推測通りの結果になったので、よかったよかった。
というわけで
今回はこの辺で
皆様、健康でよい一年になりますように
今年もよろしくお願いいたします