A と B を交互に切り替える処理でハマった話
TVのリモコンを握っている状況をイメージしてください。
TVが点いていない状態で電源ボタンを押すと起動して、点いている状態で押すと待機モードになります。
どちらの操作も同じボタンを押すことで切り替わります。
このように、A と B の2つの状態があって、一つの関数を呼ぶだけでスイッチングできないかなと思って試してみました。
実行するたびに、2つの処理を交互に切り替えたいので、引数で切り替えるのは無しです。
ようするに関数を単純に呼び出す(Call)だけでスイッチングしたいのです。
呼び出す側は「関数の中身なんか知ったこっちゃねぇ。」という状況が理想。
さらにシンプルなノードでできると尚良し。でやってみたのがこれ。
XOR ノード は 「排他的論理和」というやつで、同じものが来たら反転するというひねくれものです。違うもの同士は足します。↑の場合チェックボックスにチェックが付いている状態なので、
結果をすぐに変数にセットしてるので、内容が反転したことになります。
できれば変数を使わない方法でシンプルにできないかと思ってやってみたのがこれ。
結果はというと・・・
ここでようやくハマった話。
この MultiGate ノードを使ったつなぎ方は一度経験していて、当時はうまくいってました。で今回は「なんで?」となったのです。
結論を言ってしまうと、MultiGateノードは関数内に置くときは取り扱い注意 です。
単に「ランダムな結果を返せ」だったら is Random にチェックを付ければ問題ないです。今回のように上から実行ピン(Out 0 → Out 1 → Out 2 ・・・)を順番に流す場合はうまく働いてくれないことが分かりました。
関数の外に置いてみるとうまく働いてくれます。
Epicの公式ドキュメントにそれらしい記述が見つけられなかったので、当たり前の仕様なのか、バグなのかはプログラマじゃないのでなんとも言えないですが、ちょっと謎です。
もっとシンプルに切り替えるノードを思い出しました。FlipFlop ノードです。
「MultiGateはそういう仕様なんだ、でもFlipFlopなら状況を打開できるかも・・・」
と淡い期待を抱きつつ・・・
こちらも関数内に置いて使うと、Aのピンしか流れません。
外に出してみるとうまく動きます。
結局、外部から呼び出してスイッチングしたかったので、カスタムイベントにつなぐことで解決しました。
これでバッチリです。
ちなみにマクロの中で使う分には問題なく動作します。
ですが、そのマクロを関数の中に置くと、切り替わらないという結果になります。
あくまでも推測ですが、
切り替えるには、状態を保持しておく値が必要で、関数内からはその値が参照できなくなるんじゃないかと思ってみたり。
ではでは
今回はこの辺で。
ステキなノーディングライフを!
5分で作る マテリアルを使わないゲージ
超簡単お手軽ゲージを作ってみます。マテリアルは使いません。
Widgetブループリントを一つ用意します。
キャンバスに配置するパーツは3つ。
ゲージ用のキャンバスとゲージの下敷きは同じ大きさにします。下敷きは暗めの色にしておきます。
ゲージ本体の「Image」をキャンバスの子供にしたら、設定をサクッと変更します。
まずはAnchors(アンカー)を右下のやつに変えたら、
すぐ下にあるOffset関連の値をすべて0.0にします。
カラーを適当な色にしたら、
最後にキャンバスパネルの isVariable のチェックを入れて完成です。
編集モードをグラフに切り替えて、MyBlueprint のタブから、Function(関数)をひとつ追加します。
中身は以下。
コンパイルしてエラーがなければ保存して完成です。
レベルから確認してみます。
レベルブループリントを編集します。
再生してみると、
スペースキーを押すたびに長さが変化します。
完成です。
実際に時計見ながら作ってみたのですが、5分かからなかったです。
見た目には安いですが、このスピード感は大事です。
ゲージ一本でゲーム性やバランスが大きく変わるのはよくある話です。
ではでは
ステキなゲージライフを!
最近ハマったつなぎ方
ちょっとネタが無くなってきたのもあって更新ペースが落ちてます。
なので自分のウッカリでもさらしてみようかなと。
それは思ったような値にならず、原因も分からず、しばらく首をひねっていたつなぎ方です。
まずUMGでパーツを置いて、Widgetブループリントからいい感じにサイズを計算して調整しようとしました。
下図は 160x256 サイズの”Image”です。
これを、下のようにつなぎました。
計算した値を別のところで使いたかったので変数に保存しています。
ここで察しのいい方は気づかれていると思います。
Imageパーツのサイズをゲットして、タテ方向だけ1/16 にしてサイズを変更しています。
果たして、変数 Value の値はどうなっているでしょうか?
再生すると、パーツの見た目には うまくいっているように見えます。
でも、
答えは、 Value = 1.0 です。
え?
だって 256を16で割ったら16でしょ? なんで???
実際には 256 ÷ 16 = 16 したあとで、さらに 16 ÷ 16 = 1 となっているからです。
なんと割り算が2回計算されているのです。
SetSizeノードに割り算の結果が渡されたあとで、次は変数に値を渡すためにもう一度Imageパーツのサイズを取得して(このとき既に16になっている)16で割っています。
見た目に、割り算ノードのあたりで計算が済んでいるように見えるのと、同じピンから取り出してるので、同じ値が出てくると思ってしまったのが原因でした。
正しくは以下。
変数に値を入れない場合でも、値を確認しようとしてPrintStringノードをつなぐと・・・
1.0 という数値が表示されます。
PrintStringノードが値を表示しようとして、2回目の計算を行ってしまうためです。
では以下の場合はどうでしょう。
無事 16.0 という数値が表示されます。Imageパーツはというと問題なく 1.0 にならずに表示されています。
おそらくこれも2回計算していますが、PrintStringノードは、SetSizeノードのように結果を反映しないので、問題が起こらないのです。
この辺りのロジックが理解できるまでしばらくの間、首をかしげっぱなしでした。
以前に 乱数を発生させるノードでも同じようにハマったのを思い出しました。
例えば下のようにつないだ場合、
画面には、2つの異なる数値が表示されます。
以後気をつけます。
ではでは
ステキなノーディングライフを!
スタッフロールをつくる 《完結編》
鶏肉は柔らかいのより噛みごたえのある方が好きです。
で前回の続き。
名前を表示するための器が用意できたところで、次に必要なのは中身です。
スタッフロールには関わった多くの人々の名前が載るので結構な行数になることが多く、それをブループリントの中で管理するのはさすがにちょっと躊躇われます。また、スタッフロール用の情報を集めて整理するのはExcelやテキスト系エディタの方が向いています。
というわけで今回CSV形式のデータを扱います。詳しくはヒストリアさんとこのブログにあります。
[UE4] CSVデータを扱う方法 DataTable編 | historia Inc - 株式会社ヒストリア
CSVは『カンマせぱれいてっどバリュー』の頭文字を合わせた用語で、簡単に言うと「カンマで区切った値」ということになります。Excelだと簡単に書き出せるのですが、Excelを持ってないのでテキストエディタで作りました。
いくつかのデータをカンマで区切るのですが、今回4つのデータで構成します。
Index番号 , 表示タイプ , 名称(文字列) , 次の行までの待機時間(秒)
用意したWidgetは3タイプ。表示タイプを『グループ』『パート名』『人名』を0~2の数値で扱うことにします。で、できたのが以下
,NameType,NameString,NextInterval
0,0,STAFF,2.0
1,1,ROSE,1.0
2,2,Abigaile,1.0
3,2,Acropolis Romantica,1.0
4,2,<>Alphonse Dauder<>Anthony Meilland,1.0
5,2,<>Bienvenue<>Benjamin Britten,1.0
6,2,<>Cassandra<>Cioccofiore,1.0
7,2,<>Dorothy Perkins<>Gloria Mundi,3.0
8,1,DAHLIA,1.0
9,2,Anto Norma,1.0
10,2,<><><>Azumabeni<>Ben Houston<>Blookside Snowball,1.0
11,2,<><><>Devon Liam<>Freedom Fighter<>Gregory Stephenl,1.0
12,2,<><><>Happy Face<>Hoshitsukiyo<>Lavender Giantsl,3.0
13,1,TULIP,1.0
14,2,<>Dalvey Snow<>Cardinal Mindszenty,1.0
15,2,<>Finola<>Flaming Prissima ,1.0
16,2,<>Honoonomai<>Lambada,1.0
17,2,<>Maywonder<>Murasaki suisho,1.5
18,2,Page Polka,1.5
19,2,Ruby Prince,3.0
プレーンテキストなので Tab文字 を入れれば見やすくなりますが、文字として扱われてしまうのでCSVとして書き出す直前に置換して消すといいです。
文中の <> は分割するためのデリミタ用の文字です。
この内容で、拡張子 .csv を付けて保存するとUE4でインポートできます。
インポートする前に用意するアセットがあります。Structureです。
ストラクチャーを作ったら適当に名前を付けて編集を開始します。編集と言っても変数を登録しておくだけのものです。
表示タイプ(Int型) , 名称(String型) , 次までの待機時間(Float型)なので3つ。
4つのデータを仕込んだはずですが、今回 Index番号については特殊な扱いをするので変数にはしません。
追加したら保存して閉じます。
いよいよインポートします。作ったCSVファイルをコンテンツブラウザにドロップすると下のような小さなダイアログが出てくるので、先に作っておいたStructureをプルダウンリストからアセット名で選択します。
OKするとDataTableアセットのエディタが開きます。
問題なければ左上のFile メニューから 保存 して閉じます。
このエディタからも内容の編集が可能ですが、スタッフロールについてはReimportをオススメします。名前の収集がメールベースというケースがほとんどで、最後までExcel等で管理した方が修正も楽ちんでお手軽です。
Reimportは、コンテンツブラウザのアセットアイコンの上で右クリックすると簡単にできます。
器と中身が揃ったので、表示する処理を作っていきます。
ブループリントアクターを使ってWidgetを表示します。
まずは、変数を2つ作って、Event Begin Play のところででセットします。
中央の見慣れない色の変数は、 UserWidget型の変数です。作る際にClass を選択するのがポイントです。
Make Array ノードをつないで、用意してある3タイプのWidgetアセットをセットします。
次に、メインとなるカスタムイベントを作ってつないでいきます。
まず最初に、DataTableアセットを取り込みます。
DataTableを取り込むノードは2つ用意されているようで、getdata で検索します。
Get Data Table Row ノードは Indexの値をName型に変換して、RowNameピンにつなぐとヒットすれば、その内容を取り出すことができるノードです。青いピンにまとめられているので、Breakeノードで分解すると変数ごとに振り分けられたピンが出てきます。それを使ってどんどんつないでいきます。
図の Wd Credit Text (実際は wd_CreditText)という名前の変数は Create Widgetノードの 右にあるReturnValueピンから、一度 Promote to Variable(変数化)してから配列化したものです。今回インターフェイスを使ったしくみが活かされている部分がここです。
左の Create Widget ノードにはまだどのWidgetが入るか確定していません。確定していない証拠に ReturnValueピンから作った Wd Credit Text の型は User Widget型のままです。普通ならClassの部分にセットしたWidgetアセットの型になるはずです。そしてその型が確定しているからこそ中の関数やイベントを呼び出せるのです。ところが確定していないのに中に作ったイベント StartMove を呼び出すことができています。これがインターフェイスという仕組みなのです。StartMove ノードの右上に 封筒のアイコンがついてます。ノードを取り出す際に ”start” で検索すると取りだすことができます。
インターフェイスを持っている相手なら、誰であるか特定できていなくても、そのインターフェイス経由で関数やイベントを呼び出すことができるのです。
おかげでノードのつながりがシンプルになります。
では続きを。
各Widget仕込んだイベントディスパッチャーにバインドしています。これは「移動が終わったら連絡ちょうだいね」という部分で、連絡を受け取ったあとの処理を下の赤いラインの先で行っています。
バインドもインターフェイスの仕組みでできれば、スイッチノードで分けたりキャストしなくて済んだのですが、残念ながら無理でした。Set Timer by Event ノードは指定した時間がきたらEventピンにつないだイベントを呼び出すノードです。で、どこにつなぐかというと、先頭です。
これで、Forloop などのノードを使わずに、イベントがイベントの終わりで自分自身を呼び出すカタチになります。このイベントが呼ばれると
- データテーブルから1行分のデータ取り出す
- 指定のあった名前表示用のWidgetを生成して配列に積む
- Viewportに追加してStartMoveイベントを呼ぶ。このとき名前のテキストを渡す。
- 移動完了の連絡を受け取るためにバインド
- データテーブルの指定通りにタイマーをセット
- Index変数を一つすすめておく
という流れで処理されます。
で、移動完了の連絡を受けたら、もうそのWidgetは用済みなので、メモリ節約のために削除してやります。
先にViewportの方から削除します。スタッフロールは下から順番に出てきて順番に消えていくものなので、配列に積んだ一番古いやつ=先頭から消すことで新陳代謝できます。
ほぼ完成なのですが、このイベントを呼び出さないとイベントは動きません。
そこで Event Begin Play の最後につないでやります。
ところで、このループはいつ抜け出るのか?という心配をされている方、ご安心ください。Get Data Table Row ノードが解決してくれます。
Index という変数が肝だったのです。Name型にキャストして検索。見つかれば Row Found、見つからなければRow Not Found に流れます。これで、データテーブルから該当するナンバーが無くなったらこのイベントのループは終了します。
今回も長い道のりでした。
ようやくこの作業が報われる瞬間がやってきました。
では表示してみましょう。
空っぽのレベルを開いて、作ったこのブループリントをエディタのViewportにドロップします。場所は適当で構いません。そのままPLAYボタン押せばOK。
・・・
なんかしみじみ。
自分の名前を入れてみるとより感動するかもしれません。
内容が変わったときは、リストを編集して再インポートすればすぐに確認できます。
新しいWidgetを追加する場合は、まず↓
そして
あとは、CSVデータの方に追加した表示タイプを入れればOK。
ロゴもWidgetを複製して改造すれば同じ方法でどんどん追加できます。
以上です
ではでは、ステキなスタッフロールライフを!
スタッフロールをつくる 《Widget準備編》
画面の下から出てきて上に消えていくだけの、どシンプルなスタッフロールを作ってみました。
今回用意するアセットは以下の6種類8個。
右のWidgetブループリント3つはほとんど同じ内容。
スタッフロールは、ただ名前が並んでるだけではなく、組織やグループ、セクション、パートなどの名称、協力会社さんのロゴ、俳優さんや声優さんなどは役名と対で表示したりと、結構表記のバリエーションを用意する必要があります。
今回は『グループ名』、『パート名』、『人名』の3種を作ります。
人名に関しては、1列~3列まで対応します。
まずは見た目の材料ということで、グループ名のWidgetから。
キャンバスの適当な場所にテキストブロックを一つだけ置きます。
文字サイズは 少し大き目にして他と差をつけるために色を付けます。
位置を調整する前に アンカー の設定を変更します。
決定するとキャンバスの表示が変わります。
次にSlotの中にある Anchors のパラメータを変更します。
SizeY以外を 0.0 にすると下のようになります。Position Y を動かすと移動できます。
最後に Is Variable にチェックを付けて、UMG編集完了です。
次に
Widgetブループリントを編集します。
スクロールに必要なFloat型の変数を 3つ用意します。
キャンバスに置いたTextBlockをグラフにドラッグ&ドロップしたら、Event Constructノードにつないでいきます。
UMGで配置したものをブループリントから触る場合、Slot as Canvas Slot ノードを利用します。上のグラフは、画面下から出現して画面上に消えるまでの移動量を求めて変数に入れています。とりあえずフルHDモニタ想定で以下のイメージになります。
今回選んだアンカーの設定にある PositionY は、0.0でスタートして最終位置は マイナスの値になります。そこで -1080 から サイズ(高さ)を引くことで、最終位置を求めることができます。720pだったら、 -720 から引いてやります。解像度に対して柔軟に対応する場合は、Get Viewport Size ノードがあるので、その値を利用するとさらに汎用性が上がります。
最終位置を求めるのにわざわざGet Sizeノードを使わなくても、動かしてみれば簡単に最終位置は判明します。これは、あとからサイズを調整する際、変数の値を変更しなくてもいいというのとマジックナンバーを使わなくていいというメリットがあるためです。気軽に感覚的にサイズを調整することができます。こういうちょっとした処理を仕込んでおくだけで調整の手数を減らすこともできるのでオススメです。
次に
移動が終了したことを伝えるためにイベントディスパッチャーを用意します。
追加ボタンをクリックして名前を付けるだけでOK。
とりあえず onMoveEndと名付けました。
移動させる部分を作っていきます。
Event Tick ノードにつないでいきます。
In Delta Time ピンからは フレーム毎に下図のような数値が流れてきます。
フレームというのは映画でいえばフィルムの1コマにあたります。
これは 60fpsの場合ですが 1秒を 60で割った値とほぼ同じで、直前のフレームからの経過時間を表しているそうです。若干のバラツキはありますが、ここに60 を掛けてやれば、1フレームあたり 約1という値になります。なので 変数Speedに60が入っていた場合、1フレームにつき1ピクセル進むことになります。120が入ると2ピクセルになるのでスピードが上がります。
1フレームに進む移動量をY座標に足して、限界を超えたかどうかチェックします。
越えていなければY座標をテキストブロックに反映して次のフレームへ。
越えたらイベントディスパッチャーを呼び出します。
イベントディスパッチャーは ドラッグ&ドロップしてCallを選択したものです。
一旦ここで編集を終了して、ブループリントインターフェイスを作ります。
適当に名前をつけて開いたら、右上に New Function_0 という関数があらかじめ置いてあるので名前を変更します。とりあえず StartMove と命名しました。
続けて、下のDetailsタブから、Inputs(引数)を2つ追加します。
これでブループリントインターフェイスは完成です。コンパイル→保存して閉じます。
さきほどのWidgetの編集を再開します。
編集モードをグラフにすると、エディタ上部にClassSettings というボタンがあるのでクリックしてDetailsタブの内容を切り替えます。
DetailsタブにInterfaceを登録する場所があるので、Addボタンをクリックしてさっき用意したブループリントインターフェイスをセットします。
追加できたら、グラフの何もな無いとこで右クリックして
ブループリントインターフェイス内に作った関数を探します。
関数名の頭にEvent がついている方を選ぶと以下のようなノードが出てきます。
右上にインターフェイスのアイコンがついています。
ここに最後の仕上げ。
これでWidgetブループリントは完成です。
コンテンツブラウザからこのWidgetを2つ複製します。
複製した1つ目を開いてテキストブロックの見た目を変更します。
パート名用です。
文字サイズを少し小さくして、カラーを変えています。
これで2つ目完成。
最期の3つ目は人名用。複製した残りのWidgetブループリントを改造します。
文字サイズとカラーを変更するのですが、ここで複数列の対応を追加します。
まずは編集モードをDesignに切り替えてキャンバスパネルを追加します。
その中に6つのTextBlockを入れて子供にします。
アンカーの設定はそれぞれ以下のように変更します。
レイアウトは下のような並びで配置しますが、
実際には1行に重なった状態にします。
テキストブロックの中は何も文字を入れないように空にします。
あとはカラーと文字サイズ、字詰め方向(Justify)を設定したら、Is Variable にチェックを付けて編集モードをグラフに切り替えます。
String型と、TextBlock型の配列変数を用意します。
TextBlock型は、Object Typesの中にあります。
6つのテキストブロックを配列に積みます。
移動するのは、キャンバスパネルになるので Slot as Canvas Slot ノードには、追加したCanvasPanelをつなぎます。
インターフェイスで仕込んだ StartMove関数(ここではEvent)の部分を以下のように改造します。
Parse Into Array ノードは指定した文字列(デリミタ)が見つかると分割して配列にしてくれます。
人名のWidgetはこれで改造完了です。
これですべてのWidgetブループリントが完成しました。
今回はこの辺にしておきます。
次回はデータの準備と表示する部分を書きます。
ではでは
わりと本気のコンボカウンター 《完結編》
いよいよ動作確認です。
前回の記事はこちら
わりと本気のコンボカウンター 《UMG編》 - みつまめ杏仁
わりと本気のコンボカウンター 《Widgetブループリント編》 - みつまめ杏仁
一揃いのアセットができたので、テストしてみます。
テスト用のレベルを開いた状態で、エディタを開きます。
まずはカウント用の変数を一つ用意。Int型です。
CreateWidgetから始めます。
CreateWidgetの ReturnValue ピンの上で Promote to Variable を選ぶと簡単に変数化できます。とりあえず表示位置を大まかに決めておいて、あとはバインド祭り。
Widgetの中に仕込んでおいた イベントディスパッチャーにバインドします。
バインドは「紐づける」という意味合いです。四角いピンとカスタムイベントをつないでおくと、Widget内でイベントディスパッチャーがCall されたタイミングでここに通知が来て、カスタムイベントが作動するというしくみです。
CreateWidgetした側は、好きなタイミングでWidgetに干渉できるのに対して、CreateWidgetされた側からは逆の干渉ができません。そこで用意されているのが、このイベントディスパッチャーを使ったデリゲートとインターフェイスという2つの仕組みです。
EventDispatcher をCallしてるノードと、Bindしてるノードにマウスカーソルを重ねると
デリゲートという用語が出てくるのが分かります。
今回インターフェイスは使っていませんが、これもGUIにはとても相性がよいです。
つぎに、カウントアップの呼び出し部分。
スペースキーを押すとカウントするようにしています。
最後にWidgetの関数に値を渡して完成。
再生してテストしてみましょう。
動画を貼りたかったのですが、直接はダメっぽいので諦めました。
消え方が派手だったり、確定した時の演出があると、最終のカウントがよりわかりやすくなります。
プレイヤーは視界の端で見てるので、多少派手なくらいがちょうどいいです。
というわけで
わりと本気で作ってみたコンボカウンターです。
デザイナーだけでこのようなモックアップを作ってテストしてもらい、プログラマに組み込みを依頼する流れでいけば、小さなイテレーションループで済みそうですがいかがでしょう。
ではでは
ステキなカウントライフを
わりと本気のコンボカウンター 《Widgetブループリント編》
続きです。
前回の記事はこちら。
わりと本気のコンボカウンター 《UMG編》 - みつまめ杏仁
Widgetブループリント
絵的な素材が用意できたところで、いよいよブループリントに手をつけていきます。
まずブーリアン型の変数を一つ用意。これは、「HITs」と下敷きのアニメーションを初回と2回目以降とで分けるためのものです。これを 初めから置いてある、EventConstruct ノードにSetでつないで、初期値を false にしておきます。(①)
最後に準備用の関数をつないでいます。(③)
Add to Viewport されるたびに、この関数が実行されるのは無駄なので、DoOnceノードを間に入れておきます。(②)
このセットアップ関数の中身は以下。
キャンバスに置いたImageパーツはマテリアルにパラメータノードを仕込んでいるので、パラメータに値を渡していじることで、カラーやUVを変えることができます。そのためには、Get Dynamic Material ノードが必須です。このノードにはReturnValue という出力ピンがあるので、その内容を配列に積んでおきます。
扱い方が少し違うので、「HITs」だけは配列にはしません。
このGet Dynamic Material の操作は、マテリアルを操作する直前で行ってもいいのですが、私はReturnValue(戻り値)を変数化しておくこの方法をよく使います。
メモリは必要になりますが、なんとなく処理コストが安くなる気がします。
次に 新たに変数を3つ追加します。
カウンターを表示する関数を作っていきます。
この関数はInteger型の値をひとつもらって、それを桁に分解して表示するという内容です。いつ呼ばれるかは、プレイヤー次第なのでわかりません。コンボ受付中はカウントアップするので問題ないのですが、受付が終了してフェードアウトの最中に呼ばれると問題です。かといってフェードが終わるのを待たせるのは、ユーザビリティ的に問題アリです。
そこで、フェードアウト中に呼ばれたら、フェードアウトのアニメーションを止める処理を入れます。
別の場所でフェードアウト用のタイマーをセットしていて、そのタイマーをコントロールするためにTimerHandle型の変数を利用しています。
今は↓この部分です。
次に受け取った数字を桁に毎に分解する関数を作ります。
一、十、百、それぞれの桁の有り無しを判定して、あれば0~9の数字を取り出し、なければ -1 にします。
先に作っておいた配列変数 DigitNumArray に 桁毎の結果を入れていきます。
桁を分解する方法は、割り算(÷)と剰余(%)のノードを使います。
Int型同士の割り算は、小数点以下は切り捨てになります。
配列の中身(要素)を変更するのは Set Array Elem ノードを使います。
この Set Array Elem ノードですが、あらかじめ要素が存在しているのが前提です。
あらかじめ配列の要素を用意する方法はいくつかあります。今回はノードを使わずにセトしました。配列を作ったときの初期値です。一度コンパイルすると追加できます。
ちなみに、Addノードは新しく要素を追加するときに使うもので、何度も呼び出される関数の中に置くと要素が増えることになるのと、追加する順番に注意を払う必要があります。
続きに、できた関数をつないで、さらにカウント数に応じてカラーを変える仕組みをつなぎます。
関数内では、ローカル変数という使い捨ての変数を使うことができます。
カラーを計算して利用した後は覚えておく必要はないので(この関数の外では役に立たない)ローカル変数を新しく作っています。
今回のカウントは 999まで表示可能ですが、カラーは100以上で変化しないようになっています。精度と調整のしやすさを考えて0~200でクランプします。その値を InverseLerpノードで割合に変換します。
例えば 100 だと InverseLerpノードは 0.5 を返してきます。↑の図で、ちょうど赤から紫に変化するあたりです。InverseLerpノードは 指定した範囲のどの辺にいるかを割合で返してくれる便利なノードで、マテリアルのパラメータとして相性ばっちりです。
上の例では、コンボ数が 20、40、60、80、100 を越えるごとに色が変わります。
紫色の次がいい色にならなかったので、100で変化が止まっています。
この辺は自由に加減してみてください。
というわけで今↓ココです。
次に進みます。
各桁の表示部分です。すでに数字を桁毎に分解してあるので、配列からGetノードで取り出しつつ、アニメーションの再生をマクロを使って処理しています。
マクロは同じことを何度もする場合にラクちんなので積極的に利用します。
上記のマクロは3つとも同じ内容ですが引数を変えています。
マクロの中身はこうなっています。
さらにマクロがあります。
受け取った数字から テクスチャのUVを求めて、0未満(-1)だったら 0.0 を、0以上だったら 1.0 をパラメータにしてマテリアルにセットするマクロです。
Set Vector Parameter Value ノードはベクター型のパラメータで、LinearColorの形で値を渡します。セットアップ関数で作っておいた Material Instance Dynamic型の配列からGetノードで取り出してつなぎます。
これで数字部分の表示は完成です。
次に HITs の表示です。
色の変更と、アニメーションの分岐、フラグのセットをしています。
この後、タイマーのセットをするのですが、その前に用意するものがあるので、いったんこの関数の編集を止めます。
Event Dispatcher(イベントディスパッチャー)を2つ用意します。
コンボカウントの受付終了と、退場演出のフェードアウトが終わったことを通知します。通知する相手はこのWidgetを CreateWidgetしたブループリントになります。
次に 退場演出のイベントを用意します。
カウントアップの関数から EventGraph に戻ります。
赤いのはカスタムイベントです。作ったEvent Dispatcherを2つとも投入です。
Event Dispatcherはグラフにドラッグ&ドロップして取り出します。その際選択肢が出てくるので、Call を選択します。
ようやくTimerHandle型の中身が判明しました。フェードアウトのアニメーションが終了したことを通知するタイマーだったのです。
目覚ましが鳴る前に起きてしまって、うっかりタイマーを止めずに顔を洗っていると鳴り出してイラッ・・・みたいな状況を避けるためのものです。
ここで、先ほど編集を中断したカウントアップの関数に戻ります。
いよいよラストです。
CreateEvent ノードは、作成済みの関数やイベントを選ぶカタチになるので、いったん中断したというわけです。
おつかれさまです。これでWidget完成です。
次回は、このWidgetを呼び出すところを仕上げて終了です。