みつまめ杏仁

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

ゲームパッドとマウスでカーソルを動かす 《後編》

前回の続きです。

早速Widgetを準備していきます。まずは 子Widgetから。

 f:id:hiyokosabrey:20200225205536p:plain


キャンバスに Image を置いて、TextBlockを重ねます。

とりあえず今回は280x280にしました。

 

f:id:hiyokosabrey:20200225205659p:plain

 

今回見た目と機能をシンプルにしたかったのが理由ですが、Buttonコンポーネントでも大丈夫。TextBlock は後から文字列を差し替えるので、Is Variable にチェックを付けています。

 

次に見た目をアニメーションで用意します。

 

まず カーソルの乗っていない Default

f:id:hiyokosabrey:20200225210747p:plain

f:id:hiyokosabrey:20200225210755p:plain

 

次にカーソルの乗った Focus

f:id:hiyokosabrey:20200225210834p:plain

f:id:hiyokosabrey:20200225210845p:plain


カーソルが離れた時 Unfocus すこし余韻を持たせるためにフェードさせます。

f:id:hiyokosabrey:20200225210942g:plain

f:id:hiyokosabrey:20200225210955p:plain

 

アニメーションは完成。

最後に確認。

f:id:hiyokosabrey:20200225211310p:plain

アニメーションを一つも選択していない状態で、キャンバスの見た目が Default と同じ状態 になっていることを確かめておかないと、表示を開始した時に意図しない状態で現れます。

 

 

これでキャンバスのエディットは終了。次はブループリントです。

 

Widget の仕事は3つ。

  • マウスカーソルの検出
  • 検出した際に親に通知する
  • 見た目の変化

 

まず下準備として 親Widget に通知するための数値を保持しておく変数を用意します。

この変数は 親Widget から渡されてくることになるので、 Expose on Spawn にチェック付けます。Compileした際に Warning が出るので Instance Editable にもチェックを付けます。名前は ButtonID としました。

f:id:hiyokosabrey:20200226110628p:plain

この預かった数値を、マウスカーソルを検出した際に 通知します。

その通知の仕組みを Event Dispatcher(イベントディスパッチャー) が担当。

 

Event Dispatcher を追加して適当な名前を付けます。

f:id:hiyokosabrey:20200226111709p:plain

できたら、値を受け取って渡すためのピンを追加します。

f:id:hiyokosabrey:20200226113008p:plain

ピンの名前は先の変数と同じ ButtonIDとしました。

 

次はマウスが乗った時に検出する関数が用意されているので、オーバーライドします。

f:id:hiyokosabrey:20200225214053p:plain

プルダウンで大量に出てくるので、On Mouse Enter を選択。

f:id:hiyokosabrey:20200226111935p:plain

この関数のオーバーライドは、アセットのクラスによって内容が変動します。さすがにWidgetはUIに関連するアセットなので、入力関連が多数用意されています。

 

選択するとグラフに赤いイベントノードが現れるので、先に用意した変数とイベントディスパッチャーをつなぎます。

f:id:hiyokosabrey:20200226112955p:plain


これで、3つあった仕事のうち、2つの準備が整いました。残りは1つ。

  • マウスカーソルの検出
  • 検出した際に親に通知する
  • 見た目の変化

 

作ったアニメーションを再生するイベントを用意します。

このイベントは、自分で再生するのではなく、親Widget から呼び出して再生するようにします。マウス以外にキー入力によっても再生する必要があるからです。

 

UMGのアニメーションって、再生中に別のアニメーションを再生すると、先に再生しているアニメーションを止めてくれるわけではないので、意図しない見た目になってバグか?と思えるような結果になることもしばしば。再生する際に事前にアニメーションしているものがあれば止める仕組みを用意する必要があります。わりと面倒なのでオススメの仕組みを紹介しておきます。

 

まずは Widget Animation の変数を一つ用意します。

f:id:hiyokosabrey:20200226135938p:plain

名前を CurrentAnim(現在のアニメーション)としました。

これを使ってマクロを2つ準備します。

 

forceAnimStop

f:id:hiyokosabrey:20200226140233p:plain

再生中だったら止める、再生していなかったらなにもしない、というマクロです。

 

startInteraction

f:id:hiyokosabrey:20200226140429p:plain

PlayAnimation という名前のノードがあるので、スタートインタラクションという名前にしました。Setノードの右にピン、地味に便利ですよね。

 

このマクロを使って、アニメーション再生用のイベントを用意します。

 

強制的にデフォルト

f:id:hiyokosabrey:20200226141012p:plain

 

強制的にフォーカス

f:id:hiyokosabrey:20200226141122p:plain

 

強制的にアンフォーカス

f:id:hiyokosabrey:20200226141135p:plain

 

 この方法だと、直前に何らかのアニメーションが再生中でも、確実に止めることができます。事前に用意しておいた WidgetAnimationの変数をハンドラーとして使用することで、状況に依存しないフローを組むことができます。後からアニメーションの尺が変わっても問題なく動作します。プロジェクトのマクロライブラリに置いておくといいかもしれません。

UIはユーザーが操作するので、タイミングなんて予測できないし、可能な限りタイムラグのないレスポンスが期待されます。

 

一応これで必要な機能は揃いましたが、仕上げにもう一つボタンのラベルを書き換える仕組みを用意します。

Text型の変数を追加します。

f:id:hiyokosabrey:20200226142634p:plain

 

この変数を Event Construct でTextBlockにつないでセットします。

f:id:hiyokosabrey:20200226142931p:plain

 このつなぎ方は最初の一回のみなので、途中でボタンのラベルが変更になる場合を想定するなら、関数を用意しておくのがベスト。

 

これで 子Widget 完成です。

 

 

ここからは 親Widget を準備していきます。

f:id:hiyokosabrey:20200226144301p:plain

さっそくキャンバスに WrapBox を配置します。

f:id:hiyokosabrey:20200227022555p:plain

今回 子Widget のサイズを 280x280にしたので、WrapBox のサイズは、 余白を2pxと想定して3個並ぶので、852x852としました。

キャンバスはこのくらいにして、グラフを編集していきます。

 

まず初期化のための関数を用意します。プロトタイプなら特に不要ですが配列のセットが大きくなってグラフが不格好になるのでここに格納する感じです。実際のゲームの場合メニューボタンを表示する際、セーブデータの内容や進行状況によってボタンの状態を変える必要があります。そのための場所としても使えます。

 

まずは一番大事な フォーカス位置を覚えておくInt型の変数と、ボタンをラベル用の配列をセットします。

f:id:hiyokosabrey:20200227021951p:plain

indexCurrent という名前にしました。

ラベルは Text型の変数を作って配列にします。

f:id:hiyokosabrey:20200226145509p:plain

f:id:hiyokosabrey:20200227022257p:plain

 

今回この関数は初期のフォーカス位置とボタンのラベルを持たせているだけです。

特に戻り値もないので、 Return ノードは置いていません。

 

まずはこの関数を Event Construct につないで、ボタンになる 子Widgetインスタンス化するための ForLoop ノードをつなぎます。ループ回数は 0 から 8 の 合計 9 回。

f:id:hiyokosabrey:20200226164313p:plain

続きはこんな感じ

f:id:hiyokosabrey:20200227015057p:plain

ForLoop で複数回すことで CreateWidget ノードが 子Widget を次々にインスタンス化するので、結果的に量産することになります。

f:id:hiyokosabrey:20200227114146p:plain

インスタンス化したらすぐに配列にお取り置きしています。これで 子Widgetたちを 番号で管理できるようになります。配列に取り置きしつつ、ReturnValueからの同じ青いラインで バインディング や パディング の設定をして最後に WrapBox Add Child します。順番については特に制約とかはなさそうですが、ひょっとしたらあるかもしれません。

 

バインドは 子Widget に作っておいたイベントディスパッチャーの名前を探します。

f:id:hiyokosabrey:20200227113124p:plain

このノードはイベントにつながないと、コンパイルした際にエラーになるけど、回避するために行ったり来たりすると、説明がややこしくなりそうなので、いったんループ処理の全貌を載せます。

 

で、エラーを消すためにバインドして受信したときに呼び出されるカスタムイベントを用意します。

f:id:hiyokosabrey:20200227115253p:plain

Force~ という関数が2つ登場しますが、これは繰り返し同じつなぎ方をすることになるので Collapse Function して作ったのですが、内容は以下になります。

f:id:hiyokosabrey:20200227115657p:plain

f:id:hiyokosabrey:20200227115707p:plain

配列に格納した 子Widget たちに対して、指定した番号の持つ関数を呼び出しているだけです。アニメーションの再生処理してるイベントですね。

 

これで、先ほどのエラーが出ていたバインドノードが解決できます。

f:id:hiyokosabrey:20200227120125p:plain


これでマウスを動かしたときに、フォーカスおよびハイライトの切り替えができたことになります。

 

レベルブループリントからビューポートに追加してテストしてみましょう。

f:id:hiyokosabrey:20200227120929p:plain

PlayerController が持っている Show Mouse Cursor を 有効にしておくと再生した時にマウスカーソルが表示されるようになります。

f:id:hiyokosabrey:20200227132727g:plain

 


残るは キーボードとゲームパッドの入力対応。

 

Widget を 0~8 の Index番号で扱うので、マウスの時と同様に CurrentIndex を増減すればいいだけです。

今回キレイに3x3のグリッド状に並んでいるので、計算でどうにかしたかったので、タテ(上下)方向とヨコ(左右)方向でそれぞれカスタムイベントを作りました。

 

moveUpDown

f:id:hiyokosabrey:20200227144902p:plain

moveLeftRight

f:id:hiyokosabrey:20200227144912p:plain


このイベントには、それぞれ -1+1 が渡されてきます。左方向は X-1、右方向は X+1、上方向は Y-1、下方向は Y+1 というふうにイメージしています。

WrapBox内の並びは左上が 0 で、右下が 8 です。タテヨコに移動するように計算してして、はみ出たらIndex番号を更新しないという仕組みです。

f:id:hiyokosabrey:20200224111533p:plain

ヒントは

タテ方向は、上下に移動するたびに ±3 なので、3を掛けて ±3で計算します。

ヨコ方向は、現在地に±1した結果に対して3で割ると余りは 0~2 なので %(剰余)を使うと便利。

ちょっと難しかったのが、マイナスになった時と、最大数を超えた時の判定です。

なるべくブランチノードを減らしたかったのもあって論理和  OR  ノードを使っています。

この辺の作りは並ぶ数や最大値が変わったり、Disable状態のものをスキップするかしないかなどで、処理の仕方が変わってくるので、臨機応変な作り方が求められます。いろんなシチュエーションで作り慣れておくしかないのかも。

 

最後の仕上げです。

このままだと表示開始した時、ハイライト表現が無くて、操作していいのかどうか伝わりません。ForLoop 処理が終ったところでハイライトするようにします。

f:id:hiyokosabrey:20200227150433p:plain

 

Widget は以上です。

 

 

プロトタイプということにして、レベルブループリントでキー入力の判定を取ります。

f:id:hiyokosabrey:20200227151055p:plain

f:id:hiyokosabrey:20200227151234p:plain

New Var 0 は ビューポートに Add to Viewport する際にPromote to Variable しておいたやつです。テストなんで横着しています。

 

ようやく完成です。

 


[UE4]ゲームパッドとマウスでカーソルを動かす

 

いかがでしょうか?

状況によってはカスタマイズが必要になると思いますが、ひとまず基本的な原理はおさえられていると思います。カーソルといいつつ正確にはフォーカスおよびハイライトの遷移なんですけどね。

まぁそれっぽいキャラを子Widgetに仕込んでおいて、表示をON/OFFするとか、以前に記事で紹介していますが、親Widget側に用意したカーソルキャラをフォーカスの場所をトレイルするようにすると、カーソル感がアップします。

 

ではでは

ステキなカーソルライフを!

 

 

 

今回の失敗

実は最初カーソルを上下左右にループするように作っていましたが、並んでいる数が少なすぎて見た目に混乱しそうだったので、ループをやめたという経緯があります。

作ってみて試さないと得られない貴重な知見でした。

あと、マウスカーソルの検出に、Enter(入ってきた)とLeave(出ていった)があるのですが、作りはじめのころ 子Widget の方で両方に対応してしまっていたので、マウスカーソルが9つの子Widgetから完全に離れてしまうと、見た目にハイライト表現が消えてしまうので、キー入力するときにわからん、となっていたのがなかなか解決できずに悩んでいました。結局、Leave の検出はやめて、完全に 遷移は親Widget に任せることにしたらスッキリと解決しました。

 

 

 

マウスカーソルの表示について(追記: 2020/3/18)

以下の案件をご相談いただいたので、さっそく試してみました。

 

  • マウスおよびキーボードを操作しているときはマウスカーソルを表示
  • ゲームパッドを操作しているときはマウスカーソルを非表示

 

PlayerController で あらかじめ Show Mouse Cursor を 有効にしていたので、これを やめればいいのでは? と思い試してみたのですが、ダメでした。

f:id:hiyokosabrey:20200318224134p:plain


で、次にやってみたのが、Input Mode 系のノード。

f:id:hiyokosabrey:20200318223808p:plain
Set Input Mode Game And UI でひとまず、思ったような挙動になりました。



入力を受け取るたびに、セットするのもなんかノードが勿体ない感じがします。

ふと、レベルブループリントで一度つないでおけばいいんじゃないの?と気が付いて試してみました。

f:id:hiyokosabrey:20200318215146p:plain

が、だめでした。残念。

公式のドキュメントで詳しく触れてそうな気配がなかったのですが、探し方が足りない気がするので、いずれもう少し踏み込んで調査したいと思います。とりあえず今回はこれでなんとかなると思うのですがいかがでしょうか?

 

ちなみに、マウスを操作しているかどうかは、マウスの移動量をみて判定しています。

Widgetの関数に OnMouseMove というのが用意されているので、今回はこれを オーバーライドして利用しました。

f:id:hiyokosabrey:20200318220827p:plain

MouseEventピンから、Get Cursor Delta でマウスの移動量を取り出せるので、これでマウスに触れているかどうかを判定します。

ブランチノードの右にある Switch~ ノードは、 操作しているデバイスをアイコンで説明するために用意したカスタムイベントです。今回の記事を動画にする際にコッソリ仕込んでいたものです。

 こんな感じです。

f:id:hiyokosabrey:20200318221538p:plain

画像をあらかじめ3つ用意しておいて、表示・非表示を切り替えるというイベントです。

f:id:hiyokosabrey:20200318221852g:plain

ゲームパッドとキーボードの方は、レベルブループリントで Switch~ を呼び出しています。

f:id:hiyokosabrey:20200318222152p:plain


まずはこんなところですけど、ちょっと自信がないので、ツッコミ等々あれば是非是非。

 




 

 

ゲームパッドとマウスでカーソルを動かす 《前編》

ゲームUIに 「カーソル」は当たり前の存在でした。以前は。

最近タッチデバイスで遊ぶゲームが増えたので、ゲームUIの仕事を志望する新人君に「カーソルってなんですか?」って訊かれる日がやってくる日はそう遠くないかもしれません。とはいえ、現状コンソール機はまだまだ現役だし、PCは基本マウスを無視するわけにはいかないし、市場は圧倒的にタッチデバイスが優勢だし、プラットフォーム毎に分かれているけれど、できる限りマルチプラットフォームでコスト回収を目論むことも多々あるので、結局UI制作関係者がこの難問を解決しなきゃあならんのはまだまだ続きそうですが、みなさまいかがお過ごしでしょうか。

 そういえば、これ、

       f:id:hiyokosabrey:20200223115815p:plain   

『マウスカーソル』 って最近言わなくなってきたみたいですね。今は『ポインター』という方が一般的だそうです。ジェネレーションギャップです。Gギャップとか略すとグラフィック系の用語みたいになるのがいいですね。よくないか。UE4にはまだ MouseCursor 関連のノードあるので大丈夫だと思う・・・

 

 さてさて

 以前から チラホラとTwitterでマウスとゲームパッドの処理がめんどい、というつぶやきを見るたびに、いっちょやってみるか! とマウスを強く握りしめたりしてましたが、なかなか実際に試してみるとこまでいきませんでした。今では少し反省しています。で、ついにやってみました。先日Twitterに動画をあげたやつです。

 

f:id:hiyokosabrey:20200223220242j:plain

 

いざ試してみると、なかなかうまくいかなかったりしましたがなんとかなりました。難しかったのは、カーソルの制御で、理想とする ふるまい は、

  • 選択肢の中でハイライトまたはフォーカスされているアイテムは一つだけ
  • ゲームパッドでもマウスでもハイライトまたはフォーカスを切り替えることができる

の2つ。

 

すこし逸れますが、

『カーソル』が ある画面と、無い画面、最近のUIデザイン入門書などで語られる指南はタッチ入力やWebブラウザのUIを基本としているので、この『カーソル』の有無を絡めた話をしていないことがほとんど。ゲームUIの勉強をするにはまず『カーソル』を理解するところから始めるのをオススメします。

 

話を戻して UE4のUMGで設計イメージを図で説明してみます。

まず用意するアセットは2つ。

f:id:hiyokosabrey:20200223141726p:plain

 

親のWidget には、後から 子Widget を格納する WrapBox を持たせます。

f:id:hiyokosabrey:20200223142032p:plain

 

この WrapBox の中に並ぶアイテムとして、子Widget を追加します。

f:id:hiyokosabrey:20200223144256p:plain

WrapBox に追加された 子Widget たちは、追加した順に番号で管理します。

f:id:hiyokosabrey:20200224111533p:plain

Widgetゲームパッドとカーソルキーの入力を受けてフォーカスを切り替えます。

 

 

Widget が機能として持つのは、

  • マウスカーソルが乗ったかどうかの判定
  • マウスカーソルが乗った際に 親Widget への通知
  • 見た目の変化

 の3つ。

 

f:id:hiyokosabrey:20200223213543p:plain

 

マウスカーソルが乗った時、新たにフォーカスが切り替わるので、親Widget に通知します。

f:id:hiyokosabrey:20200224112146p:plain
 

通知を受け取った 親Widget は、キー入力の時と同じように、フォーカスの切り替え処理を行えばOK。 基本的に 子Widget の見た目の変化は、親Widget が動かします。

 

しくみはこんなイメージになりますが今回はここまでにします。

次回はこれを実際に組んでいきます。

 

Photoshopのブラシ触ってたら面白そうなのができたので、頑張って手書きにしてみましたけどどうかな。

 

ではでは

すてきなカーソルライフを!

 

 

 

 

 

 

 

スコア表示のときに

 ふと思いついて作ってみたシリーズ。

 よくスコアの表示などにゼロ埋めとかゼロパディングとかいう表記法を見かけます。あらかじめ最大桁数を晒すということは、桁が埋まらないうちはプレイヤーの非力さを示し、埋めていたゼロが無くなってくると今度はカンストを示すことになるので、それとなくネガティブな印象を与えてしまうことがあります。ゲーム画面のデザインで桁の多い数字を表示する場合はその辺も考慮しつつデザインを考えることになります。

 もとはデジタルな計器などのインジケーターに良く使われる LED(7セグ) や VFD(蛍光表示管)、電卓の液晶、古くはピンボール台のニキシー管等々、物理的なレイアウトの制限によって最大表示桁数が設けられているのをデザインモチーフとして利用している、そんなところでしょうか。ニキシー管カッコイイですよね。確かシュタゲでも登場していたような。ニキシー管が何か気になる人は  nixie tubes で画像検索してみてください。

 

 ゲームのUIとしては、ただ数字を表示するだけでは、何の値か分からないので一緒に見出しを付けます。ゼロパディングはその見出しとの距離を縮めてくれる効果もあります。距離が近い方が視線の流れが易しくなります。

 

f:id:hiyokosabrey:20200128013051p:plain

 

f:id:hiyokosabrey:20200128013055p:plain

 

 

今回のネタはこのゼロパディングの部分を分けて表示します。

 

 f:id:hiyokosabrey:20200128013718p:plain

 

これをHorizontalBoxを使ってやってみます。

まずはキャンバスに HorizontalBoxを一つ。

f:id:hiyokosabrey:20200128215130p:plain

 

中に TextBlock を 2つ入れます。ヒエラルキーはこんな感じ。

f:id:hiyokosabrey:20200128224209p:plain

 

それぞれ適当にゼロを入れておいてカラーを調整。

f:id:hiyokosabrey:20200128220505p:plain

 

デフォルトだと左詰めなので、右詰めになるように設定を変えます。

(さくっとうまくいかなくて以外にややこしかった)

f:id:hiyokosabrey:20200128224213p:plain

f:id:hiyokosabrey:20200128224216p:plain

 

ここからはブループリント。

 

まずは変数を4つほど用意します。Integer型が3つ、String型が1つ。

f:id:hiyokosabrey:20200128230354p:plain

 今回桁数は最大8桁にするので、digit_max の初期値は 8 を。

f:id:hiyokosabrey:20200128231219p:plain

digit_string_zero の初期値はゼロを 最大桁数より1つ少ない 7桁分入れておきます 。

f:id:hiyokosabrey:20200128231223p:plain

 

次に、スコアをTextBlockに反映する関数を用意します。

f:id:hiyokosabrey:20200128231646p:plain

ゼロ埋めする数を事前に計算している前提。

 

 カスタムイベントでスコアを受け取るようにする。先に作った関数は右下につないでます。

f:id:hiyokosabrey:20200128233547p:plain

桁数を調べるのは、対数関数の log を使ってみました。いったん文字列型にキャスト(型変換)して文字数を調べる方法もあるけど、キャスト処理のコストが高いのでやらない方向で。

 対数関数は、底(BASE)を 10 にすることで、10進法での桁数が分かるというものです。

 ざっくりとした説明ですが、例えば桁を表す百の位の 100 は10の2乗、万の位は10の4乗です。つまり乗数は桁数より1少ない数であることに気づくと思います。この乗数で表わされるのを指数、その逆である対数というものが log で表わされるそうです。

 本来の用途ではない気がしますが、ちょっと気になったので log で出てくる数字を調べてみました。

 参考までに、65535 という数字を log ノードに入力してみると、 4.8164733037652... という値が出てきます。それをInt型の変数にキャストする際に自動で挿入されるTrancateノードによって 4 という数字になります。99999 という数字なら、4.999995657... となって、10000 だと 4 、100000 だと 5 になります。

 ということなので、使う際には +1 します。また、log に0は無効なので、ブランチノードで0以上かどうか判定してから渡しています。

 

できました。

f:id:hiyokosabrey:20200129002011j:plain

 0~9の文字幅が揃ったフォントだといい感じです。

 

カウントアップのアニメーションを試してみました。

f:id:hiyokosabrey:20200129230716g:plain

 

文字幅に差があるフォントの場合。

f:id:hiyokosabrey:20200129231511j:plain

Neuropolはお気に入りなんですが、極端に1の幅が狭いです。

 

アニメーションするとガタガタします。 

f:id:hiyokosabrey:20200129231929g:plain

 

今回の方法を使わずに、重ねてしまうのもアリかもしれません。ニキシー管ぽくなります。

f:id:hiyokosabrey:20200130003753g:plain

 

 

これで完成ですが、ちょっとだけブループリントをいじります。

スコアをTextBlockに反映するために作った関数があります。

f:id:hiyokosabrey:20200129235047p:plain

 実は、後から Collapse Function して作ったものです。スッキリして悪くないと思うのですが、中でどんな変数が使われているか、中を確認しないと分からないので、関数を作った本人以外はモヤモヤしそうです。

 これをわかりやすくする方法があります。わざと中の変数をパラメータとして渡すようにします。

 

 結果がこれ。

f:id:hiyokosabrey:20200129235845p:plain

 

f:id:hiyokosabrey:20200130000445p:plain

 これで何の変数を使って処理しているか分かるので、処理をイメージしやすくなります。つなぐ手間は増えますが、関数名だけのノードよりわかりやすくなると思うのですがいかがでしょうか。関数の汎用性も向上するのでオススメです。

 

ではでは

ステキなスコア表示ライフを!

 

 

 

 

 

 

 

 

2020年

 年が明けました。今年はコトホギをご遠慮させていただいています。

 昨年末に母がALSから解放されたのを見送って、年明けに仕事の締め切りとかもあって、時間と精神共に余裕がなく、何やら慌ただしい年末年始となりました。

 いきなり重い話から始めてしまいましたが、最近ようやく仕事も落ち着いてきました。遅ればせながら年頭ということで、なんとなく目論んでいることなどを書くことにします。

 私はアンリアルエンジン(以下 UE4)が大好きです。職業はUI制作を主業務としております。過去に開発でUE4を経験して以来、ずっと惚れ込んでいるわけですが、ゲームUIの開発において、その技術の習得や検証に適した環境が無いという悩みを解決してくれたのがUE4でした。UI専門なんで利用範囲は限られますけど。

 ゲームのUI制作はUI用の絵素材をプログラマを通じて表示してもらうことがほとんどです。プログラマがいてくれないと始まらないのが現状です。UI制作のスキルを向上させるには、場数を踏むしかなくて、よりたくさんのUI制作を経験するのが確実ですが、プロジェクトに参加できない状況では切ないものがあります。

 そのピンチを救ってくれるのが UE4というわけです。ゲーム開発は自社で環境を整備できる体力のある会社も多いですが、最近では Unity や UE4 といったゲームエンジンをメインに据えて開発されているディベロッパーさんも増えてきている印象です。

 ちなみに、Unity での開発も経験しました。こちらもアーティストがとても参加しやすいエディタだと思います。ただUIを制御するビヘイビアスクリプトが必要で、C# で書くことになります。ここがまずプログラミング経験がないと、臆するところになるかと思うのです。

 UE4 のブループリントは、テキストではなくノードを並べて組み上げていくビジュアルスクリプト。テキストベースのコーディングに比べてエラーになりにくく処理の流れが分かりやすいのがウリ。ブループリントの扱い方を覚えるだけで、それなりにゲームUIをカタチにすることができます。アーティストだけでUIプロトタイプが作れます。

 というわけで、UE4普及のためとUE4の面白さを啓蒙する目的で始めたこのブログでもありますが、一度ブログの外に出て、勉強会的なものを主催してみようかと、ついに思い至ったわけです。

 ちょっと前置きが長くなりました。とりあえずなんか文字だらけでさみしかったので、最近食べた バインミーの写真を貼ってみます。

f:id:hiyokosabrey:20200121233203j:plain

 パクチーで具が隠れてます。バゲットがアツアツでザクザクしてて芳ばしくてすごく美味しかった。

  

 で、まだ内容などはボンヤリしてますが、勉強会的なものについてまずは今考えていることを挙げてみます。

 

対象

  • ゲームUIアーティストを目指したい方
  • UE4で作るUIに興味のある方
  • なんか新しいUIを作ってみたい方

 

場所

  • ワークショップ等のできるレンタルスペース
  • 今のところ大阪市

 

方法

  • ノートPCを会場に持ち込んで実演とか?
  • 事前にお題を出しておくとか?
  • UI相談所?
  • もくもく会とかに憧れてたりするので、お菓子持ち込んで気軽に情報交換とかでもいいな、などと考えています

 

狙い

  • UE4で自身のアイデアを存分に組み込んだ架空のUI画面を作れるようになる。これを動画にしたり実行形式にしたりして、就活用ポートフォリオの武器にできる
  • UE4を活用してUIインタラクションの検証や プロトタイピング技術を磨く
  • などなど

 

 まだまだ準備や考えなくちゃいけないことがたくさんあると思うけど、ひとまず今年やろうとしてることで大きなやつを書いてみました。初めてのことなのでうまくいくか分からないけど、集まらなかったらぷちコン用に一人もくもく会でもやろうかな。

 

 他には、置いて行かれないようにもっといろんな機能に触れていきたいし、ブログの更新ペースも上げていきたい。ぷちコンで賞取りたい。おいしいもの食べたい。海行きたい。というわけで、お役に立てるか分かりませんが、ネタが続くうちは記事を書いていこうと思います。

 

ではでは

今年もUE4でステキな出会いがありますように

みなさまのご健康とご多幸をお祈りいたします

 

 

スクリーンスペーステクスチャで遊ぶ

 もうすぐ大晦日、あっというまに令和も2年、このブログも2015年の12月から書き始めてから4年を迎えました。UMGに偏った内容でありながらも良く続いてるなと思います。読んでくださってありがとうございます。すこしでもお役に立てているなら幸いです。

 

 ここ半年ほど大きいネタばかりだったので、今回は軽いやつでいこうかと。

 マテリアルをいじっていて見つけたノード。

f:id:hiyokosabrey:20191225000355p:plain

 この ScreenPosition ノードをUMGに利用すると、いろいろ面白い表現ができそうです。

 

追記 2020/09/21>>

ScreenPositionはヒストリアさんのブログですでに記事になってました

historia.co.jp

アスペクト比による補正についても言及されています。

<<

 

 

 まず簡単なのはこれ。

f:id:hiyokosabrey:20191225234014j:plain


 キャンバスには適当に Image と TextBlock をちりばめています。

f:id:hiyokosabrey:20191225001235p:plain

 このパーツにマテリアルをセットしますが、スクリーンスペーステクスチャとして以下の画像を用意しました。8x256pxです。

f:id:hiyokosabrey:20191225001606p:plain

 スクリーンスペース(画面座標空間)のUVで貼るから、スクリーンスペーステクスチャと命名しています。特別な仕様などはありません。

 

 マテリアルは超シンプル!

f:id:hiyokosabrey:20191225001916p:plain

 これだけです。

 この ScreenPosition から流れてくるのは、UMGのパーツが画面(スクリーン)に描画する際のUV座標です。

 

 たとえば下図のようなレイアウトがあったとして、

f:id:hiyokosabrey:20191225004347p:plain

 

 スクリーンスペース用テクスチャをマテリアルで重ねることで、

 

f:id:hiyokosabrey:20191225003327p:plain

 

Photoshopクリッピングレイヤーのような見た目を作ることができます。

 

f:id:hiyokosabrey:20191225004722p:plain

 

 UMGのパーツにセットできるマテリアルは、描画の際に乗算されるようです。

 なので、UMG側でパーツのカラーをいじることで、また違った色味を作ることができます。

 この方法で色を付ける場合、テクスチャはグレースケールでいいので、とても容量の節約ができます。

 

 今回のサンプルで使用している雪の結晶は4種類です。同じマテリアルを使用している限り、自由に配置しても場所に応じたスクリーンスペーステクスチャが掛かります。

f:id:hiyokosabrey:20191225011657p:plain

 

 おまけとして、この4パターンをテクスチャとして貼るためにちょっとマテリアルを改造したので、載せておきます。

 マテリアルインスタンスを使ってバリエーションを出せるようにしました。まずマスターマテリアルを用意します。

f:id:hiyokosabrey:20191225012913p:plain

続き

f:id:hiyokosabrey:20191225013151p:plain

これでマテリアルインスタンスを作るとパラメータがこうなります。

f:id:hiyokosabrey:20191225214231p:plain

Index(ScalarParameterValue)のところに 0.0 ~ 3.0 を入れます。

 

UVが 0.5刻みなのでシンプルに手入力でもいいですね。

f:id:hiyokosabrey:20191225014009p:plain

こちらの方がGPUの負荷が少ないです。

f:id:hiyokosabrey:20191225214353p:plain

 

テキストブロック用にもマテリアルインスタンスを用意します。

ブールパラメータ―を使って分岐してるので、falseにするだけです。

f:id:hiyokosabrey:20191225214614p:plain

 

 

マテリアルインスタンスが用意で来たら、キャンバスのパーツにセットしていけば完成。

f:id:hiyokosabrey:20191225214749p:plain

グラデ―ションだけでなく柄やノイズを入れてグランジ感を出しても面白いです。

 

例えばこんなグレースケールテクスチャを、アルファチャンネルに掛けてやれば、

f:id:hiyokosabrey:20191225224608j:plain

f:id:hiyokosabrey:20191225233622j:plain
こんな感じにできます。

 

タイルパターンとグラデーションだとこんな感じ。

f:id:hiyokosabrey:20191225233259j:plain


ScreenPositionとUMG、いろいろ楽しめそうです。

 

 近年モニタの高解像度化でUIに必要なテクスチャ解像度も上がっています。少ない容量で解像度を稼ぐにはチャンネル数を減らすのが効果的で、シルエットで見せるフラットデザインと相性がバッチリです。フラットデザインは、背景の情報量が多いゲームだと際立つので使いやすいのですが、どうしても色味が乏しくなってしまい派手さが出ないのが残念ではあります。そこでこのマテリアルです。そろそろフラットデザインも見飽きたかな・・・というプロジェクトで提案してみてはいかがでしょうか?

 最近だとAppleArcadeの Shinsekai Into the Depths でそれらしい表現が見られます。

 

ではでは

今回はこの辺で。

 

 

 

体力ゲージ的なあれこれについていろいろ

アドベントカレンダー9日目の記事になります。

 このブログでは普段アンリアルエンジンでのUI制作に関することを書いています。

 今回は久しぶりにエンジンは起動しないで、ゲームUIのネタとして、体力ゲージ的なやつを取り上げてみようと思います。

  体力ゲージ的 という曖昧な言い回しになるのは、役割が同じでも見た目が違うものも含めてしまえという、ちょっと欲張ったネタにしようと思い立ったからです。 

 

ちょっとだけ昔の話を

 さてさて、ビデオゲームが世に生まれてから、何かしらのゲージを見ないゲームはないんじゃないかと思えるくらい、当たり前のようにみかけます。ゲージの無いゲームを探す方が難しい気がします。いろんなゲージがある中でも、体力ゲージとかHPゲージ、LIFEゲージといった、ゲームの世界に生きているキャラクターが行動不能になるまでを視覚化した表現は、ゲージがなくなること=ゲームオーバーやミッション失敗などプレイのやり直しを求められることが多く、ゲージが残りわずかになると、プレイ継続不可能な状況が迫っていることを否応なしにプレイヤーに突きつけてきて、緊張感を煽る存在でもあります。黎明期のアーケードゲームは1発でも当たったら死ぬという厳しさで、その無慈悲さを緩和するために残機が増えたり、シールドゲージがついたりしました。

 パーティや部隊を組んでプレイするゲームは、ゲージが無くなっても他のメンバーが生きていたら続行不能にはならなかったりしますが、どちらにせよゲームのメカニズムにおいてかなり重要な要素として位置付けられていることは間違いないと思います。

 一方で、プレイヤーが倒さなければいけない敵などに紐づく体力ゲージは、効率のいいプレイを探るモチベーションにもなったりします。

 

 ただ長さが変わるだけの表示に、一喜一憂し、乾坤一擲の勝負に出、背水の陣で冷や汗を流し、盛者必衰を悟る体力ゲージ。 

 古今東西いろんなゲームでゲージに翻弄されるささやかな人間ドラマが繰り広げられている事実を知り、またそれを意図的にデザインしてほくそ笑むことができれば、生粋のUIデザイナーだと胸を張っていいんじゃないかと思います。

 

 ゲームのUIデザインは ゲージに始まりゲージに終わる

 

 

 この業界に長く身を置く者として、作ってきたゲージ類は数え切れません。今までたくさんゲージを作ってきた経験則を元に、ゲージをデザインする際に考慮すべきポイントを書き連ねてみました。ゲージのカタチを考える時や、企画の仕様に抜けが無いかの確認等に役立てられればと思います。

 

 ちょっと小難しく親父語りを始めてしまいましたが、そろそろ今回のネタに移ろうと思います。ここからは画像が増えますよ。

 

 

そもそも体力ゲージ的なやつって?

 体力ゲージと言ってしまうと、棒グラフ状のゲージに限定されてしまう恐れがあるので、あえてぼかした言い回しにしてみました。ゲーム内のポジションが同じなら体力ゲージでいいじゃん、というのもちょっと乱暴な気がして、これ!、というコトバが見当たらないのですが、面倒くさいのでとりあえず「体力ゲージ」と呼ぶことにします。 

 体力ゲージの見た目はさまざまですが、大きく分類すると3タイプに分けられます。

f:id:hiyokosabrey:20191202200538p:plain

 

 中でも棒ゲージタイプは、カーブしていたり、太さが均等じゃなかったりと、いろんな派生形がありますが、基本的には長さが 可変か固定か の2系統に分かれます。

 

 

 3タイプそれぞれに向き不向きがあります。

 

棒ゲージタイプ

f:id:hiyokosabrey:20191206010744p:plain


 最大値に対して今どのくらい、というのがわかるというのが最大の長所。

 可変する量が無段階なので、アナログ的な補正や調整がしやすい。

 情報量に対し表現に必要な面積が少なく済み、長さを表現できるなら、シンプルな形状から複雑なものまでデザインの幅は広くとても汎用的で扱いやすい。

 長さが固定の場合は成長して最大値が増えても比率でしか表現できないので、成長している実感は得られにくい。また、最大値がゲージのドット数より多い時、残りわずかな状態で、見た目に消えてしまうことがあるので注意が必要。

 

 

数値タイプ

f:id:hiyokosabrey:20191206010801p:plain

 ズバリの数値が表れているので、具体的な値での増減が分かりやすいのが長所。

その反面、直截すぎて桁数の表現が心理的にどう作用するかが個人差があって読みにくいのが難点。

 ウソが付けないぶん後から補正やら調整が入れにくい。

 最大値を常に表示するために、分数表記が採用されることも多い。

 文字による表現は、脳内で変換が必要になるので、棒ゲージに比べて直観的ではないため、リアルタイム系のアクションゲームでは避けた方が無難。

 また、シリーズを重ねるタイトルの場合、仕様の拡張によるインフレの懸念もある。

  

 

アイコンゲージタイプ

f:id:hiyokosabrey:20191206010822p:plain

 

 定量的に増減できるので、ダメージ量や回復量について説明するのが簡単なのが長所。

アイコンのデザインによるところが大きく、あまり大きくできないため、細やかな増減を表現するには不向き。数が増えてくると見た目にうるさくなりがち。

 体力が減った場合、仕様的に最大個数を保持するかしないかで遊び方が変わる。保持する場合は、増えること=成長 で安心感が得られ、保持しない場合は、増えること=保険、という扱いになり、補充できないと辛くなる。

 増減の方向として、リニアに変化するタイプや角度で変化するタイプなどがある。

 

 

 

 もちろん不得意な部分を補う形で3タイプを混ぜて使う、いわゆる合わせ技という表現もあります。

 

f:id:hiyokosabrey:20191208150003p:plain

 ゲージで全体の割合を、数字で今の値を示したり、ゲージのカタチが分かりにくい代わりに数字で割合を示したりというのがあります。

 

 

 デザインする

 体力ゲージをデザインに落とし込むときにあれこれ考えながらベストなカタチを模索するのですが、ゲームのメカニクスを顧みず、見た目だけでデザインすると、後で不幸に見舞われるかもしれません。遊ばせ方を事前にすり合わせておくとそれほど迷わずに済みますし、ゲージの比重が明確だとレイアウトを考えるとき少しはラクになれます。

 まずはいろんな仕様に対するゲージのふるまいや普段私自身が気を付けていることを挙げていくので、参考になれば。

 

 

成長要素があり、最大量が増える?

f:id:hiyokosabrey:20191204014312g:plain

 

 

  f:id:hiyokosabrey:20191205223658p:plain 長くする。可変できる仕組みが必要

  

  f:id:hiyokosabrey:20191205223723p:plain 桁を増やす

 

  f:id:hiyokosabrey:20191205223741p:plain アイコンの数を増やす

 

 成長要素等で伸びていくタイプ。レイアウトに余裕があればそれほど問題はない。

 ただ、余白の取り方で最大の長さを予測される恐れがあるので、ゲーム進行を気取られないようにしたいなら伸びしろの扱いに注意。

 

 

 

表示領域に制限があるけど増やしたい

f:id:hiyokosabrey:20191204235222g:plain

 

 

  f:id:hiyokosabrey:20191205223658p:plain 色で本数を表現する。細かく増やせないし気づきにくい

          カラフルになりがち。後述のバフ表現等と衝突する可能性

 

  f:id:hiyokosabrey:20191205223723p:plain 数字を小さくしたり、少し重ねたりすれば可能だけど

 

  f:id:hiyokosabrey:20191205223741p:plain サイズ違いのアイコンを用意して x5とか x10 を表現

 

 かなり無理してる感がある。どうしても後から仕様を付け足した感が出るので、成長するかどうかの『握り』=仕様確認は大事。「なんとかならない?」と言われた場合は、合わせ技である程度解決できる。レイアウトを確定させるためにも早い段階で詰めておきたい。

 

 

 

割合が分かればいい

f:id:hiyokosabrey:20191205001519p:plain

 

 

  f:id:hiyokosabrey:20191205223658p:plain 問題ない。リング(環状)にするのもいい

 

  f:id:hiyokosabrey:20191205223723p:plain パーセント表記にする

 

  f:id:hiyokosabrey:20191205223741p:plain 向いていない

 

 最大値が大きくなると変化量が小さくなるので、ゼロ付近が視認しづらくなる。ゼロになってもゲームオーバーにならないゲームでは有効。

 表示面積が小さくできるので助かる。

 

 

 

満タン時の違いは必要?

f:id:hiyokosabrey:20191205225925g:plain

 

 

  f:id:hiyokosabrey:20191205223658p:plain 色相を大きく変えなければ色替えがベスト

 

  f:id:hiyokosabrey:20191205223723p:plain 難しい

 

  f:id:hiyokosabrey:20191205223741p:plain 効果が薄い

 

 格闘ゲームのパーフェクト K.O. や、満タン時のみダメージ軽減など、発動に特別な条件がある場合は、違いをある程度分かりやすくする必要がある。

 

 

 

どんな減らせ方がいい?

f:id:hiyokosabrey:20191207094305g:plain

 

 

  f:id:hiyokosabrey:20191205223658p:plain できるだけアニメーションさせたい

 

  f:id:hiyokosabrey:20191205223723p:plain カウントダウン。アニメーションの時間に注意

 

  f:id:hiyokosabrey:20191205223741p:plain できるだけアニメーションさせたい

 

 一気に減らしてしまうと、変化に気づきにくいので、できるだけアニメーションさせたい。その方がヤバイ感というか緊張感が伝わりやすい。ダメージのタイプによっ演出をいれると豪華になるうえに、原因が分かって納得度を上げることができる。たとえば物理ダメージの場合は振動させたり、魔法ダメージだとそれぞれのエレメントに合わせたエフェクトを乗せてみるとか。

 

 

 

減った量を判らせたい?

f:id:hiyokosabrey:20191207113129g:plain


 

 

  f:id:hiyokosabrey:20191205223658p:plain ゲージを2重にしてアニメーションさせる

 

  f:id:hiyokosabrey:20191205223723p:plain カウントダウンとマイナス分の表示を追加する

 

  f:id:hiyokosabrey:20191205223741p:plain アイコンのカタチに依存するので難しい

 

 

 ダメージを受けた瞬間にダメージ量を判りたいというのが、普通になってきているので、実装不可避な印象もあるけど、棒ゲージ以外は得意じゃないので、ゲージの近くか別の場所で減量分を表示するのがベター。

 重要なのは、ダメージを受けた時、ユーザーはどこを見ているか? という点に気を付けることです。そのあと、ゲージに視線誘導させるか否かで、演出やアニメーションのタイミングを調整します。

 

 

 

状態異常などバフ表示が必要?

f:id:hiyokosabrey:20191206000951p:plain

f:id:hiyokosabrey:20191205235216g:plain

 

 

  f:id:hiyokosabrey:20191205223658p:plain ゲージの色を大きく変えたり、エフェクトを乗せたり

 

  f:id:hiyokosabrey:20191205223723p:plain 色替え程度しかできない

 

  f:id:hiyokosabrey:20191205223741p:plain アイコンの色を変える。可能であればカタチも変える

 

 まずは、わかりやすく色を変えてみる。棒ゲージはそこそこ面積があるので、UVスクロール系のアニメーションをオーバレイしたりすると効果大。ステータスを表すアイコンを添えるなど、ゲージの表現以外の要素も含めたり、他の条件と被らないかなど、情報設計のコストは割と高め。

 色替えでわかりにくければ、動きを付けると目立たせることができる。

 

 

 

残り少なくなったらどうなる?

f:id:hiyokosabrey:20191207000700g:plain

f:id:hiyokosabrey:20191207002914g:plain

 

 

  f:id:hiyokosabrey:20191205223658p:plain ゲージ本体または、ゲージの背景を点滅して強調

 

  f:id:hiyokosabrey:20191205223723p:plain 数字を色替え点滅 

 

  f:id:hiyokosabrey:20191205223741p:plain アイコンの色または、枠を点滅して強調

 

  面積が小さくなった状態で点滅させても目立たない場合は、枠や下敷きを点滅させる。点滅のカラーはゲージカラーとも相談して慎重に選ぶ。赤色の点滅が一番心理的に響くけど、プロジェクトのカラースキームによっては、赤を使いたくないデザインもある。

 あとちょっとという状態が重要なのに見づらいという場合は、ゲージのサイズを見直そう。

 ピンチ表現を作り始めてようやくいろんな制約や問題に気付くこともある。点滅させたくない場合もあったりするので、どうすればピンチを伝えられるかのアイデアは日ごろから色んなゲームをプレイしてストックしておきたい。

 

 

 

回復表現はある?

f:id:hiyokosabrey:20191207171608g:plain

f:id:hiyokosabrey:20191207180508g:plain


 

  f:id:hiyokosabrey:20191205223658p:plain アニメーションさせる

 

  f:id:hiyokosabrey:20191205223723p:plain カウントアップさせる 

 

  f:id:hiyokosabrey:20191205223741p:plain アニメーションさせる

 

 回復は嬉しいもの。多少動きがあると嬉しさもアップ。動きを考えるときに、嬉しい表現と残念な表現についても分かりやすく区別できるよう意識して設計する。例えば赤点滅=ネガティブ表現、白点滅=ポジティブ表現 というのを決め、それを徹底するようにするだけで、パラメータ―やステータス表現でもプレイヤーの学習コストを下げる効果が期待できる。

 

 

 

 だいたいこんなところでしょうか。

 体力ゲージは、とにかく減らされることがプレイヤーにとっては最大の不利益となります。 したがって減ることの理由を、納得いくように表現して差し上げるのが、UIデザイナーの使命でもあります。情報量を増やし過ぎると初見で拒否られるし、少なすぎると謎感が上がって不親切な印象を与えてしまいます。UIデザインって匙加減がとても難しいのです。

 

 

 気をつけたいカタチ

 体力ゲージは、ゼロになるとペナルティがある以上、残りわずかであること、つまりピンチであることを表現することが重要になります。

  あとどのくらい? いまどれだけ減った? というのも大事なので、一方の太さが変わるようなゲージデザインは常時確認したくなる体力ゲージでは避けるべきです。

 f:id:hiyokosabrey:20191207103857p:plain

 物理的にピクセルが少なくなるので残り僅かであることを視認しづらい。

 反面これをチャージ系のゲージだとして考えると、ある程度溜まりきるまでは意識しない状態にできるし、溜まりきった時に最大面積になってようやく満タンになったよ!スキル使っていいよ!というアナウンスができます。

f:id:hiyokosabrey:20191207104918p:plain

 ONとOFFがハッキリしていて、あとちょっとで溜まりそう、という体力ゲージとはまったく逆の期待感を煽ることができるカタチです。まさにチャージ系のゲージに向いているといえます。

 

 とここまで書いておきながら、体力がゼロになっておしまい、とは逆の、ダメージが最大になったら戦闘不能、という詭弁のような発想で、このデザインでも緊張感を煽ることは可能です。SUN値やピヨリなどのスタン系ゲージでも使うことができます。

f:id:hiyokosabrey:20191208015228g:plain


 ザックリとですが言ってしまうと、大事な局面で必要な情報がしっかり視認できればなんでもアリです。まぁゲームUI全般に言えることでもありますが。

 

 全体のカタチとゲージの増減のカタチが合ってないのも時々見かけます。

f:id:hiyokosabrey:20191208142932g:plain



 

 

 棒ゲージの作り方いろいろ

 カタチがシンプルで構成するパーツも少なくて済みます。いろいろアレンジもしやすく、周囲をデコレーションで差別化できれば大体完成できるということで、扱いやすいのも魅力。

 用意するパーツは最低限2つあれば十分。ゲージ本体と、最大量が分かるための下敷きか枠。デザインは皆さんの素晴らしいセンスを発揮してもらえればバッチリなので、ここではゲージの増減についてちょっと技術的なところを書いていきます。

 

 ゲージの増減方法は大きく分けて3つほどに分けられます。

 

 簡単でコスパがいいのがスケーリングする方法。

 ゲージにグラデーションや模様などを入れていると、拡縮した際残念な見た目になるのでシンプルなベタ色か、スケールに影響されない方向にグラデーションを入れるのが無難。

f:id:hiyokosabrey:20191207120758g:plain

 

 と、思わせておいて、実は発想を変えると可能です。つまり見た目の下敷きを上から被せる方法。下図は重なりを斜めから見たイメージ。

f:id:hiyokosabrey:20191207120416g:plain

 

 

 2つめはステンシル等のアルファマスクや、シェーダーを使って画面の表示ピクセルを削っていく方法。これだと、下敷きを上に載せるというトンチを使わずに、ゲージにグラデーションや模様をいれることができます。

 

f:id:hiyokosabrey:20191206230534g:plain

f:id:hiyokosabrey:20191206230242g:plain

 シェーダーを使いこなせると面白い表現が可能なので積極的に使っていきたいですね。

 

 

 3つめはUVスクロール。これはゲージの先端部分がカーブしていたり、斜めになっている場合に効果的。テクスチャのオフセットを動かして増減させます。3Dメッシュを使えば、複雑な形状でも、ゲージにすることができます。下の例はちょっと贅沢に下敷きを別に用意している場合。

 

f:id:hiyokosabrey:20191207132805p:plain

 

 f:id:hiyokosabrey:20191206232400g:plain

 

 アルファチャンネルを使わないで作ることも可能で、デザインにもよるけど、下敷きが不要でパーツが減る分処理が少なくできる。無双系やタワーディフェンス系のゲームで大量にゲージを出す場合は特に効果的。

 ただの長方形だと安っぽいので、斜めにしたりすることが多い体力ゲージ。頂点を変形して斜めを作ると、UI描画の際アンチエイリアスが掛からないことが多いので、ピクセルの荒れを回避するなら頂点は長方形のままでUVスクロールがオススメ。

f:id:hiyokosabrey:20191206233535p:plain

 UVスクロールで動かす場合、テクスチャにゲージの長さの2倍の領域を確保しないといけないけど、テクスチャの設定をWrap(繰り返し)ではなくClamp(繰り返さない)設定にすると小さいテクスチャでもいい感じにできる。

 

 

 おまけとしてシェーダーを使ったテクニックをひとつご紹介。

f:id:hiyokosabrey:20191207135255g:plain

 アルファチャンネルのUVを動かさずに、RGBチャンネルのUVのみをスクロールさせます。絵に合わせてスクロール量を調整すれば完成。表示パーツはたった1枚で済むのでエコです。テクスチャのやりくりができれば、きっとプログラマにも喜ばれるはず。

 

 

かつては・・・

 大きなスプライト描画やポリゴンが登場するまでは、今のような自由なサイズのキャラを表示する仕組みがなかったり、解像度が低く拡縮でキレイに表示できなかったので、8x8とか 16x16とかのチップを並べてゲージを作っていました。ゲージは1ドットずつ変化します。これをプログラムで書き換えていくのです。

f:id:hiyokosabrey:20191206235118p:plain

 格闘ゲームなんかは1ピクセルがきちんと表示されていないとだめなので、丁寧に細かくパターンを用意していました。

 

 

開発にまつわる体力ゲージ

 ゲームグラフィックの表現力が上がってより繊細になるにつれてゲージのようなゲームゲームした表現を忌み嫌う向きもそれなりに増えてきているように感じますが、いつ死ぬか分からない緊張感はストレスにもなりえます。そのストレスから解放してくれるのがゲージだったりするわけで、このあたりのジレンマを解決しておかないと開発終盤にニッチモサッチモという事態に至ることがよくあります。

 「没入感」というキーワードを盾にしてUI要らないとか言い出すプロジェクトは、モーション(キャラクターアニメーション)やVFXの作成コストに跳ね返ることを考慮していないことが多く、最終的に作成コストが比較的安いと思われているUIに「やっぱり・・・」という事態に。

 没入感と一緒に語られるダイエジェティックなUI表現も、アートディレクターがUIデザイナーを兼任しているプロジェクトでもない限り、UIデザイン側から発信するのはとても難しいと思います。

 

 UIデザイナーがプロジェクトにアサインされる前にすでに検証やプロトタイプが進行していることはフツーです。プログラマがちょいちょいと作った簡素なゲージが表示されていることが多くて、開発中は見やすいし分かりやすいと当たり前のように鎮座しているのですが、どこかのタイミングで製品クオリティのデザインにしないといけません。ですが、シンプルイズベスト! 下手にデザインしたものに差し替えようものなら、分かりにくいとクレームが来ることもたまにありますし、ずーとそれでデバッグしてきたから生半可なデザイン差し替えでは納得されないし、じゃぁ、と手を入れなさすぎるとデザインをサボってるかのような目で見られたりします。

「これ、そのうちデザイン変わるんだよね?」

「え!? えぇ、も、もちろんです」(遠い目)

 

 マジで棒ゲージ最強です。これ以上分かりやすい見た目はないです。実際に作るのにほぼコストはかかりません。誰でも簡単に思いつくしものすごく手間がかかっていない仕事として見られています。仕様を色んな角度から眺めて検討し、あーでもないこーでもないと悩みぬいた挙句の棒ゲージ。他の可能性やロジックをシェイプアップして作った究極の一本!それでも、

「これって、仮キャラ?」

「え!? まぁ、今デザイン考えてるとこなんすよね~」(さらに遠い目)

 

 やっぱり体力とかライフといえばハートだよね。形も可愛いし。ハートを並べるのは分かりやすくてワールドで受けが良さそう!

「なんか、ゼルダっぽすぎない?」

「!・・・そうっすね。」(心も遠くへ)

 

 数字は桁が増えた時のインパクトは捨て難いよね。ちょっと生生しいけど、オシャレなフォントを使えば・・・ほら、いいカンジ!

「今回の仕様だと3桁ぐらいまでしか使わないんだけど」

「じゃぁ、後ろにゼロ3つくらい付けましょうよ」(汗)

「いや さすがにバレるだろ」

「・・・」(温泉行きたいな)

 

 

 

最後に

 一度でもゲージ類を作ったことがあれば、ゲージのパッと見簡単そうに見えて実はとても奥が深くて、いろいろ考えさせられるということを体験されていると思います。

 

  ゲージを笑う者はゲージに泣く

 

 いつか言ってやりたいのですが、ゲージを作るのはUIデザイナーの仕事。十分思い知ってるからこその任せてもらってるんだと思いますが、ゲージを笑うやつは、たぶんゲージを作ることはないんだろうなと。残念ながら。シンプル過ぎてアレンジしにくいのをなかなか判ってもらえないですが、頑張って新たな地平を見つけたいと日々チャレンジし続けたいと思います。

 

  ゲージに泣く者は、さらにゲージに泣く

 

 全然救われない格言でシめようと思いますが、いいゲージができた暁には、アドカレに記事を書こうと思います。ゲージについて語り合ったりお題を解決するゲージデザインOnlyのイベントとかあっても面白そうな気がします。ちなみにすごいのができれば発明になるので、特許を申請できますよ。

 え?この記事のゲージがダサい?

 もちろん仮ですよ。サンプルですよ。お試しですよ。本気出してないだけ。あはは・・・・は。

 

ではでは

ハッピークリスマス!

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

 

 

※今回の記事に載せているアニメーションGIFは、すべてPhotoshopのフレームアニメーションで作成しました

 

 

 

 

 

 

 

 

 

 

キャラ絵のテクスチャを作って表示する《おまけ編》

 前回前々回とキャラ絵をUMGでゲームっぽく作って表示する記事を書きましたが、いいねをたくさんもらえてありがたい限りです。さらにスポットライトに取り上げてもらえて

 びっくりするやら気恥ずかしいやらで、とりあえず浮かれたい気持ちをなんとか堪えつつおまけ編を書きていきます。

 

  できたのはこんなやつ。

f:id:hiyokosabrey:20191124151549j:plain

 

 さてさて、4人パーティのRPGなので、キャラの表示が4人分。それぞれを状況に応じてコントロールする必要があります。各キャラのパーツをクリックするとリアクションするとこまで、とりあえずグラフに並べて確認できました。

f:id:hiyokosabrey:20191124151049g:plain

 まだ、クリックしたら暗くなるだけです。

 

 そのノードがこんな状態。

f:id:hiyokosabrey:20191124142521p:plain

 せっかく配列にキャラ表示Widgetを4つ分入れているのに、なんだかコピペっぽい感じだし、無駄に同じ処理のイベントが並んでいます。

 

これをスッキリさせようというのが今回のネタとなります。

 

 

 中身が同じ4つのWidgetがキャンバスに並んでいて、それぞれは個別に動作はするけど、中身は同じなのでまったく同じ振る舞いをします。

f:id:hiyokosabrey:20191130205609p:plain

 これを並べて管理しているレイアウト用のWidget(以降、親、または親Widgetとします)は、それら各キャラ用Widget(以降、子、または子Widgetと書きます)を個別に扱う必要があります。

 親はいつでも好きなタイミングで子へアクセスできますが、子はバインドされていないと親への連絡はできません。

 

 親から子へバインドすると、専用のカスタムイベントを介して通知を受け取ることになります。

f:id:hiyokosabrey:20191201103305p:plain

  必然的に、子の数だけバインドノードと通知を受け取るためのカスタムイベントが必要になります。今回のパターンでは、個別の対応をする以外は全く同じ処理を必要とするのと、カスタムイベントの名前を変えないといけないので、↓ このようなセットが4つ並びます。

f:id:hiyokosabrey:20191130232255p:plain

↑左端のキャラ用  ↓右端のキャラ用

f:id:hiyokosabrey:20191130232318p:plain

 

 また、ゲーム画面の中でも、メニューボタンや機能ボタンのいくつもあるような画面では、ボタンごとに処理の方法や遷移方法が変わるために、こういったバインドとカスタムイベントの組み合わせが大量に並ぶことになります。

 

 これをスッキリさせていきますが、まずはこれから。

 

新しいグラフに引っ越す

 単純でシンプルで簡単な方法。

 エディタに最初から用意されているEventGraph 以外にもグラフを追加できます。

 Excelのシートみたいな感覚で使えます。増やすのはMy BlueprintタブのGraphsのところにある+ボタン。

f:id:hiyokosabrey:20191126225326p:plain

これでまっさらな新天地のグラフが使えるようになります。

 

コピペで引っ越しできますが、実行ピン同士をつなぐことができなくなるのでカスタムイベントを使って中継します。

f:id:hiyokosabrey:20191130210048p:plain

Sequenceノード以降を新しいグラフにペーストして、カスタムイベントを一つ追加。

f:id:hiyokosabrey:20191126232525p:plain

元のEventGraphに戻って、このカスタムイベントを呼び出すだけ。

f:id:hiyokosabrey:20191130210404p:plain

 

 セットアップや初期化のような、最初に一度だけ動かして、あとはそのままといったものを置くのに向いています

 ちょっと見えないところにやってしまうだけなので、カスタムイベントが追加になりますが、ノードの量は変わりません。あまり解決にはなってないですが、メンテナンスをする際に効率が上がります。

 

 

 ちなみに今回の例では4キャラ分のセットアップをSequenceノードを使って並べています。線を分断してコンパクトにできます。処理自体は順番に行われるので途切れません。

 

f:id:hiyokosabrey:20191201104124p:plain


 Sequenceノードはある程度のまとまりで管理できて見やすくなるし、途中や最後に追加しやすいのも便利な点です。

 

 これで再生して普通に動けば、1スッキリ成功です。

 

受け取り用のカスタムイベントを共用にする

 今回の例ではバインドから受け取った後の処理は同じでも、呼び出す関数がイベントディスパッチャーから通知のあった子が対象になるので、特定の子に対して関数を呼び出す必要があります。

 そこで有効なのが、子であるWidget自身が『誰』であるかを一緒に通知する方法です。そうすると、受け取ったカスタムイベントは、『誰』が特定できているので、同じ処理を『誰』ごとに行うことが簡単にできます。せっかく配列にして管理しているんですもの。Index番号を利用しない手はないですね。

 

 さて、同じWidgetなのに、個別の ID を持たせるにはどうすればいいか。それは、Expose on Spawn を使います。

 さっそく子Widgetを編集していきます。新しくInteger型の変数をひとつ追加します。

f:id:hiyokosabrey:20191130235213p:plain

Expose on Spawn と Instance Editable にチェックをつけて有効にしておきます。

 

 これで、このWidgetが、インスタンスとして生成されるとき(Create Widget ノードとか、どこかのキャンバスにUserCreated として配置されたときとか)に値を受け取って生まれることができます。

 この変数をイベントディスパッチャー経由で渡せるようにします。

イベントディスパッチャーを選択して、Detailタブから、Inputs を追加します。

f:id:hiyokosabrey:20191201003951p:plain

 Type を Integer型にします。

f:id:hiyokosabrey:20191201004018p:plain

 

 いったんコンパイルします。

 

 グラフに置いてあるノードにエラーが出ることがありますが、慌てずにエラーが表示されているノードの上で右クリックして Refresh Nodes を選ぶと消えます。

f:id:hiyokosabrey:20191201011328p:plain

入力ピンが増えるので、ここに先ほど追加した 変数をつなぎます。

f:id:hiyokosabrey:20191201011344p:plain

 これで子Widgetの編集完了。

 

 

 イベントディスパッチャーからの通知に変化があったので、親Widgetの方にもエラーが出ます。が、まずは、新しくカスタムイベントを新しく用意します。このイベントはどちらのグラフに置いても大丈夫。

 Integer型のピンを追加して、子Widgetを配列から取り出すようにします。

f:id:hiyokosabrey:20191201012149p:plain

 新しい受け取り準備ができました。これが共用のイベントになります。

 

 ここで、バインドノードとつながっているカスタムイベントを一掃してキレイにします。

f:id:hiyokosabrey:20191201012717p:plain

 新しくバインドノードとつなぐのは Create Event ノードです。

f:id:hiyokosabrey:20191201013103p:plain

 ↓こんなノードが取り出せます。

f:id:hiyokosabrey:20191201013132p:plain

 SelectFunction... と書かれたプルダウンから、さきほど用意した新しいカスタムイベントを探します。

f:id:hiyokosabrey:20191201013416p:plain

 このプルダウンに出てくる関数またはイベントは、パラメータのタイプと数が完全に一致してるものだけです。なので事前に作っておく必要があったのです。試しにピンの数を変えてみるとどうなるか。

 カスタムイベントの方にピンを追加してみます。

f:id:hiyokosabrey:20191201014014p:plain

 CreateEventノードはどうなっているか・・・

f:id:hiyokosabrey:20191201014104p:plain

 特に大きな変化はない様子だけど、コンパイルしてみると・・・

f:id:hiyokosabrey:20191201014136p:plain

 やっぱり。

 

 ということで、イベントディスパッチャーのパラメータ―と受け取り側のカスタムイベントのパラメータ―を一致させることが重要です。

 個人的に Create Event という名前と役割がいまいちしっくりこない感じがしているのですが、このノードで、離れたところにいるカスタムイベントをつなぐような使い方ができます。コンパイルした時点で、バインドノードに何もつながっていない場合エラーが出るので、このCreateEvent をつないで鎮めます。

f:id:hiyokosabrey:20191201014858p:plain

 

f:id:hiyokosabrey:20191201015059p:plain

 これで、受け取りのイベントは共用になったので、メンテナンスや改造が1か所で済むようになりました。

 

 エラーが無くなったところで、子に『誰』であるか特定するための固有番号を与えます。UMGのキャンバスを開いて並んでいる子を一つ選択します。

f:id:hiyokosabrey:20191201104730p:plain

 Detailsタブに新しく Default という項目が増えています。

f:id:hiyokosabrey:20191201104943p:plain

 ここに、Expose on Spawn を有効にした変数の名前が出てきているので、値をセットします。これで初期値として値を持たせておくことができます。

 

この状態で再生して変わりがなければ2スッキリ成功です。

 

バインドをシンプルにする

 まだスッキリさせる方法が残っています。

 バインドノードのTargetピンには配列をつなぐことも可能です。

 ↓このようになります。

f:id:hiyokosabrey:20191201020026p:plain

 これと、Sequence ノードに5番目のピンを追加してつなぎます。

f:id:hiyokosabrey:20191201020431p:plain

もともとあった個別のバインドノードたちはいらなくなります。

f:id:hiyokosabrey:20191201020626p:plain

 

 再生してみて何も変わらなければ、3スッキリ成功です。

 

 

 かなりスッキリしたと思います。あともう一つスッキリさせる方法があるのですが、今回はこの辺にしておきます。デフォルトの Event Graph 以外のグラフを使う方法と、Sequenceノード、CreateEventを使った方法が紹介できたので満足です。

 今回は同じ構造の子Widgetが対象なので、ForLoopを使うことも可能でしたが、まずはUIを作るうえで汎用的に役立てられるかなと思って記事にしました。

 

ではでは

ステキなUI開発ライフを!

 

 

 

 

 

おまけ

 TwitterにGIF画像を上げていた、タイマーイベントを使ったゲージ回復を一部ご紹介します。EventTickは使っていません。

 実際にゲームのプロジェクトで利用する場合はフラグの制御やらで回復中のクリックを抑制したり、キャラごとに回復速度の補正が入ったり、といろんな都合があると思います。下の例は子Widget内で処理しています。あくまでも一例ということで。

 

f:id:hiyokosabrey:20191201110637p:plain

  満タンじゃなければ、一定時間後に自身のカスタムイベントを呼び出しています。

 右端の青い変数は、Set Timer by Event ノードがReturn Value として出力するタイマーハンドラーを保持しておくもので、満タンになった時に、このタイマーハンドラーに対して停止を指示します。するとタイマーはストップするので、結果このイベントは呼ばれなくなります。上図の流れだけだと、止めなくてもSetTimerByEventが処理されないので大丈夫なはずですが保険的に入れています。入れておくとゲームの都合で止めなきゃいけない時などにこのハンドラーにPause(一時停止)の指示を出すこともできます。必殺技発動なんかのデモ再生中は止めたりしますよね。デモ技発動中にも回復していたら、デモの尺によって有利不利が出てきてしまいます。

 あとは、見た目を切り替える関数を適宜呼び出したり、回復中であるかどうかのフラグをセットしたり解除したりといった処理を追加すればいい感じになるはず。

f:id:hiyokosabrey:20191201113333g:plain

 キャラをクリックした時と満タン時にエフェクトとか出したいなーとか、妄想しています。

 以上 おまけのおまけでした。