いつもの100本ノックの前に軽く、先日のぷちコンに応募した作品について振り返ってみようかと思います。

期限いっぱいまで奮闘してたので提出してからしばらく燃え尽きてました。
第24回目のお題は「スピード」
珍しく具体的なワードだなという印象。
絵的な「速さ」の表現がブラーくらいしか思いつかなかったので、ネタ出しを諦めかけていたところにTVの気象情報にハッとなった。はるか昔 図鑑に風力の段階について書かれていて、子供心に恐怖を覚えたのを思い出し、そうかテキストでも速度を表現できるじゃないか。というところから着想を得てできたのがこれ。

ここずっとシェーダーについての記事ばかりだったので、せっかくだからUIメインでシェーダーいっぱい使ったものにして、活用例としてあげられたらと、Widgetブループリントだけで作ることを決意。
内容は
論理クイズというジャンルの設問に答えて、速度を上げていくというもの。

どちらを選択しても速度レベルは上がりますが、正しい方を選択すると多くレベルアップします。設問数が尽きる前にレベルが最大になればクリアです。
Wikipediaで速度について調べたら、速さの比較というページがあったので、速度の状況をレベル的に示す「現在速度」について、秒速の数値と説明テキストを引用させていただきました。動画に入れるべきだったのですが、慌てていて失念していたのでこの場を借りて補足とさせていただきました。
Widgetブループリント

全部で10
そのうちレイアウトを管理して動いているのが2つ。
残りは、パーツ扱い。
画面を構成するのがUIのみなので、なるべくいろんなものを動かすようにした。
今回 割り込みが多いので、タイムラインを使ったアニメーションは少なく、主にSetTimerByEvent を利用。
いくつかピックアップします。
ただテキストを表示しただけだと面白くないのと、視線を誘導する目的で一文字ずつ出現するWidgetBPを用意。

カスタムイベントで、文字列を受け取ったら、一文字ずつバラしてHorizontalBoxに追加。指定された時間を待ったら、出現開始というつくり。
Construct Object From Classノードで TextBlockを生成。
表示のたびに生成すると負荷になるので、事前にいくつか生成しておく。
以降はそれをクリンナップしながら再利用。
不等号の記号<>を動かしてみた。

マテリアルで作ったものだけど、キー入力に合わせてキャンセル的な動きをさせるのが

結構大変だった。
スタートとゴールを変数で持っていて、キー入力で書き換わる。
そのスタートとゴールを Lerp(線形補間)で遷移させるというつくり。

今回は 単位が重要な要素。段階によって変化する。
この記事を書いていてテクスチャがミスってることに気づいた(汗 ↑ の画像は修正済み。
速度の数字も桁数が頻繁に変わるし、マイクロとかはアスキー文字に含まれてないし、小数点もある。最終速度の「光年」に至っては表示桁数が16桁となるので、String型で対応することに決めた。
テクスチャででっかく表示したいのもあって、速度と単位をまとめて表記するためのルールを作った。
でそのルールに従って手で整形すると面倒だしミスりそうだったので、Javascriptで整形する簡単なHTMLファイルを作ってブラウザで変換作業。

ゼロ埋めはしたくないので、前方の空白は x 、単位は a ~ h のアルファベットに置き換え。という簡単なルール。
表示する際は、一文字ずつバラしてSwitchノードで振り分け。桁ごとに反映させて表示。

昔 Javascriptで遊んでたのが役に立った。文字列や配列の操作はこのころに覚えたので、ブループリントで活かせているのはありがたい。
数字の切り替わりのときに上下をグラデーションマスクにしたかったから、マテリアルで動かしている。

背景に流れる星も、テキスト演出同様に、事前に150個の Image をキャンバスにランダム配置。この時、サイズもランダムにしてその値を配列に保持。

あとはクイズの回答でレベルアップするごとにすべての配列の中身を1.125倍し Sizeに反映することで、全体が徐々に速度を上げつつ伸びるという仕様。
サイズと速度の伸びを別の配列にするか悩んだけど、最終的に サイズ×1.1 を移動速度にして動かしている。
Widgetのハイライトはこれくらいかな。
GameState

ステート、設問、速度テキストの管理
メインのWidgetブループリントの比重が重くなるので、ここで保持することにした。
設問等はTableアセットで持てばCSVが使えるのでエンジンへの組み込みは楽できたんだけど、当初はそれほど大きな配列を作る想定ではなかった。
BPインターフェイス

GameStateとのやり取り用。アクセスする際にキャストするのがちょっと重たく感じたので、インターフェイスを活用。

GameStateブループリントにセットすると、自分の作ったGameStateの中の関数にMessage経由で呼び出せるようになるので便利。
ストラクチャ(構造体)

設問一式と速度情報の表示で、まとめて扱うのでグルーピングする感じ。

いろいろ整形してから表示するので、String型をメインに構成。
これを配列にして、Index番号で適宜取り出せるように。
Enum

ゲームの状態を「ステート」名で識別するために使用。
Enumを変数管理しておいて状況によって書き換える。
今回決定ボタンやポップアップを閉じるときなどにEnterキーを使うようにしたので、状況に応じて意図的に弾いたり、遷移先を制御するのに利用。

テクスチャ、マテリアル、マテリアルインスタンス
マテリアルは、テクスチャアトラスからパーツを取り出すのと、カラーの統一を容易にする目的。
カラーのアニメーションも、マテリアル内に A と B の2色を持たせておいて、パラメータで切り替えるようにしたので、プロジェクト全体での色の調整箇所を少なくできる。

ParentMaterial(親マテリアル)として、汎用的に使うために用意したら、あとはマテリアルインスタンスを都度作って、UVを指定する。
各所のWidgetブループリントで散りがちなカラー管理を一括したい場合に使える手法。
タイムラインでのカラーアニメーションは何かと大変なのでおすすめ。
マテリアルインスタンスを使って、速度レベルアップの演出を作ってみたら、結構いい感じに動いてくれたので、次の記事 ゲージ100本ノック #98 で紹介します。
サウンド
キー入力時にSEを鳴らしたら、なんとなく UIの動きより気持ち遅れる印象だったので、UIが動く直前にマクロでDelay 0.2秒 を入れて組み込んでみたら気にならなくなった。

一部のSE および BGMは ポケットサウンド さんの音源を使用させていただきました
またキー入力とレベルアップ時に 効果音ラボ さんの音源を使用させていただきました。
ありがとうございます。
文字について
ロゴや見出しに「ぶっとくスピード感」をコンセプトに時間がかからないのを目指して自作しました。Asciiの半角カナをイメージ。全てPhotoshopのシェイプです。
下は斜体にする前の状態。

必要になるたびに追加していったので、こうやって全体を見渡すとバランスのおかしいところがいっぱい・・・
ウェイトの太い文字と普通の文字でメリハリをつけると、UIにリズムが生まれます。
最後に
いつもながら素敵な機会を用意してくださって、本当に有難い限りです。
今回はたまたま早くにネタを思いついたので着手できました。
UEで日々 UI制作 を頑張っている方たちへ、刺激物になれればいいなと思っていろいろ仕込んでみました。フンッと鼻で笑っていただけると光栄です。
今回は慣れないモデルの扱いに怯んだりすることはなかったので、ぎりぎりでしたが楽しく進めることができました。
ここからは告解
実は・・・
設問数を当初の予定通りに用意できませんでした。
本当は20問用意するはずでしたが、できたのは半分の10問。「比較」というのがネックで思ったより難航してしまいました。

途中から同じ設問が続くことになるけど ゲームの流れは完成していました。
設問数が少ないなら、少ないなりに判定結果を調整してしまうこともできたのですが、52段階用意した速度レベルをなんとか雰囲気だけでも伝えたかったのもあって、スコアの上昇率を調整したり設問の配列の並びを入れ替えて撮影しました。
動画編集はPremierRushです。切ってつなぐくらいしかやり方を知らないのですが、上記の細工と動画の尺でなんとか、同じ設問が表示されるのを回避しました。
まぁ 「できてないやんけ」 と言われれば、・・・ソウナンデスヨ、テヘペロ
と返すしかできないのです。
同じ設問が表示されるバグが残ってたと言い訳できればまだマシだったかもしれません。
応募を間に合わせたとはいえ、日に日に心苦しくなってきたのでここに書き残すことにしました。
まぁUMGだけで形にできたので悔いはないです。
ではでは
素敵な ぷちコン ライフを!