読者です 読者をやめる 読者になる 読者になる

みつまめ杏仁

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

Widgetで回転する数字カウンタを作ってみる

f:id:hiyokosabrey:20160114233728p:plain

前の記事でマテリアルを操作してテクスチャのUVを変更する内容を書きましたが、その応用編?です。背景が黒いのでちょっと分りにくいですが、

交通量調査とかで使ってそうなアナログなカウンタを再現してみようかなと。

まずはテクスチャ。64x1024の長方形。一文字の大きさ(UVの範囲)は 64x88です。

f:id:hiyokosabrey:20160114234519p:plain

9 の次にもう一度 0 が来ているのは、 9から 0 への移行 を表現するためです。

あと、1文字分のタテサイズが88の理由。それは、

1024ピクセル を 「01234567890」 の 11個の数字で割ると、1文字あたり タテ 93ピクセルは確実に使えるはずなのですが、93 ÷ 1024 したときに桁が多くて丸められてしまい誤差が出てしまうためです。

93に近くて、小数点の桁が 一番少ないのが、88 でした。(それでも 0.0859375 という細かさ・・・)

 

さて次に、雰囲気を出すためのテクスチャ。サイズは 32x64。

もっと小さくても良さそうですが、なんとなく。

f:id:hiyokosabrey:20160115000242p:plain

テクスチャが揃ったので、コンテンツブラウザにドラッグ&ドロップしてアセット化します。MipMapの解除と、DXT圧縮を回避したいので CompressionSettingは UserInterface2D を選択。

 

マテリアルの仕込みに移ります。

f:id:hiyokosabrey:20160115001606p:plain

 アセット化したテクスチャをドラッグ&ドロップで配置します。タテ方向(V方向)しか移動しないので、Vの値だけパラメータで触れるようにしておきます。

大事なのが Texture Coordinate ノードの設定。ここであらかじめトリミングしたいサイズを指定しておきます。

ヨコはそのままなので、 U Tiling は 0.0 のまま。

タテは 88 ÷ 1024 なので VTiling は 0.0859375 。プレビューに 数字が一つだけになればOK。

コンパイルして保存します。

 

ちなみに、Append ノード と Addノードの違いは、漢字にすると分かりやすいと思います。「追加」と「加算」です。電気のコードみたいに別々のものを1本に束ねてしまうのが Append(1本に見えるけど中身は別々に存在)で、足し算して元の状態に戻らない状態にするのが Addです。

 

次は子Widgetを作ります。一桁分のWidgetです。後から調整しやすく融通の利く作りが好きなので親子にします。親Widgetのキャンバスに表示したい桁の分を並べます。

 

Widgetを作ったらUMGのキャンバスにImageを一つ追加します。

f:id:hiyokosabrey:20160116225449p:plain

編集モードをGraphに切り替えて、まずは数字を切り替えるための関数を用意します。

適当に"SetTextureOffset"という名前にしておきます。

f:id:hiyokosabrey:20160116230418p:plain

関数の Inputノードのところで、マテリアルのパラメータに渡すための引数を Float型で一つ受け取れるようにしています。

 

数字のテクスチャを動かすための変数を準備します。

数字から数字への距離(Distance) 88 ÷ 1024 = 0.0858375 と 毎フレーム加算する値(OffsetSpeed) = 距離の 1/10 を固定の値であらかじめ決めてあるので、EventConstruct ノードに接続していきます。

f:id:hiyokosabrey:20160116231026p:plain

EventConstructノードは、Widgetがスポーンされたときに処理が走るところです。

Widgetには普通のブループリントにあるConstructスクリプトが無くて、その代わりといったところでしょうか。

 

次に親Widgetから数値を受け取れるようにします。

テクスチャの現在地のV値を保持する変数 OffsetValue と 目的地のV値を保持する変数 GotoNumber をセットする関数を作ります。

f:id:hiyokosabrey:20160116231953p:plain

今回のサンプルは開始位置が 0 スタートなので、 この関数内で現在地を0にリセットしています。基本的に親Widgetは、この関数を呼ぶだけにします。

関数は以上です。

 

さて、親Widgetが↑の関数を通じて目的地をセットしてくれます。 目的地が決まればあとは動かすだけです。

Graphの イベントTickノードにつないでいきます。

f:id:hiyokosabrey:20160116233337p:plain

Tickノードは、再生中は常時処理されるところです。

現在地にスピードを足して、目的地を越えたかどうか判定します。

越えてたら、現在地を保持している変数 OffsetValue に目的地の値を、越えてなければ素直に現在地にスピードを足した値を OffsetValue に入れます。

最後にマテリアルに反映させるための関数に OffestValueの値を渡して完了です。

 

これで子Widgetの編集は終わりです。コンパイルして閉じます。

 

いよいよ親Widgetです。

WidgetのGraphでいつものカンジでつないでみたのがコレ↓

マクロは使ってません。

f:id:hiyokosabrey:20160117210157p:plain

ForLoopで6桁分回して配置してます。CanvasPanel0 というのは親Widgetに配置したキャンバスパネルです。

割とこのつなぎ方をよく使うのですが、今回はちょっと変えてみます。

編集モード『Designer』でパーツを配置しますが、リストの下にUserCreated というカテゴリがあります。この中に作成済みのWidgetアセットがエントリされているので、さっき作った子Widgetをここから探してキャンバスにドラッグ&ドロップして配置します。

f:id:hiyokosabrey:20160117211808p:plain

コンテンツブラウザの中身を全部リストアップするので、同じ名前が出てくることがあります。その時は慌てず一旦キャンバスにドラッグすると、中身がプレビューできるので安心。間違ってたらドロップせずに静かにマウスを戻すだけ。

Detailタブで名前を付けて、Is Variableにチェックが付いているのを確認したら、編集モードをGraphに切り替えます。

この方法のメリットは、配置する際にちょっと不規則にしたりできるとこです。アナログ感がでます。

で、並べた子Widgetは変数になっているのでこれを配列にします。

f:id:hiyokosabrey:20160117213007p:plain

 このスタイルの方がシンプルでわかりやすいのですが、子Widgetを更新した際にタイミングが悪いと、関連してるWidget全部でコンパイルエラーが出たりするので注意が必要です。

配列化できたら、子Widgetの関数を呼び出すイベントを用意します。こいつが子Widgetに仕事を依頼します。

合わせて、数を6桁にバラバラにして保持する配列 "Dgits" も作ってつなぎます。子Widgetに渡すためです。配列の中身はこの後作ります。

f:id:hiyokosabrey:20160117224353p:plain

最後にこのイベント↑を呼び出す関数を作ります。

呼び出す前に数を各桁バラバラにしてやる必要があります。子Widgetが桁ごとにバラバラだからです。で、できた関数がコレ↓。

f:id:hiyokosabrey:20160117225002p:plain

PrintStringノードはチェック用なので、最終的に不要になります。

この関数は何度も呼び出される可能性と将来的に桁が増えることを考えて、Clear ノードで中身を空にしておいてから、Addノードで積み直しています。

以前の記事でも登場しましたが、 計算用のノード  ÷ の組み合わせで桁を分解します。例えば、 764592 という数字の 1000の位は4です。これを取り出すにはどうするかというと、

764592 ÷ 1000 = 764.592  ですが、整数型同士で計算すると小数点以下は切り捨てになります。Windowsにバンドルされている電卓で、プログラマ用に切り替えて計算すると下のようになります。

f:id:hiyokosabrey:20160117230215p:plain

100の位以下がどっか行きます。で %(剰余)の出番。これは割った余りなので、

764 % 10 = 4

となるわけです。

関数の最後、仕上げに先に作っておいた イベントをつないで親Widgetの編集終了です。コンパイルして保存します。

 

あともう一息。

表示する部分です。これはレベルブループリントに書きます。

Widgetを Create Widget → Add to Viewport でスポーンさせます。

f:id:hiyokosabrey:20160117231513p:plain

最後に、Widgetの関数に 0~999999 のランダムな数値を渡して完成です。

再生すると、000000から一斉にスクロール初めて、

f:id:hiyokosabrey:20160117232515p:plain

数字の小さいのから順次止まります。

f:id:hiyokosabrey:20160117232200p:plain

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

いちいちエンジンを停止・再生しないと確認しづらいので、最後におまけを追加。

f:id:hiyokosabrey:20160117233140p:plain

入力キーは何でもOK。キーを押すたびにランダムな数を目指して動きます。

 

実際の動きを再現できていないので、もう少し手を入れていこうと思います。

とりあえず今回はここまで。