みつまめ杏仁

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

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

 

 前回の記事でRPGバトル画面風のUIを作る想定で、キャラのバストアップをテクスチャにしてUMGに仕込むところまでを書きました。その続きを作っていきます。

 材料はあらかた用意できたので、あとは実用に耐えるように関数をいくつか準備します。

 

 まずはゲームの企画仕様を元に、UIで必要な処理を考えてみます。

 

1.パーティ編成がプレイヤーによって自由にできる想定

  → キャラの絵を変えられる

 

2.職業がいくつか設定されている

  → 職業の名称を変えられる

 

3.棒状のゲージで体力量を表し、必要なタイミングで更新される

  → ゲージの長さを変えられる。ゲージは比率で増減。

 

4.棒状のゲージでスキルポイントの所持量を表し、適時値が更新される

  → ゲージの長さを変えられる。ゲージは比率で増減。

 

5.四角のスキルゲージによって、使用できるまでの時間を表す

  → 任意の量で見た目が増減する

 

6.プレイヤーが編集可能なスキルのアイコンを表示

  → アイコンの種類を変えられる

 

7.キャラを使用できるまでの間のタイマーを表示

  → 任意の値で数字が増減する

 

8.キャラの絵を待機中の見た目に変更する

 

9.キャラの絵を満タン時の見た目に変更する

 

10.スキルアイコンとゲージをチャージ中の見た目に変更する

 

11.スキルアイコンとゲージを満タン時の見た目に変更する

 

 

ひとまず思いつくのはこのあたり。

まずはシンプルなタスクをこなす役割としてごく単純な機能のみを備えた関数を用意する。

 

 

今回の作りでは、いろいろとマテリアルでいじれるようにしているので、まず最初に準備として マテリアル インスタンス ダイナミック を作ってそれを変数化する。

だらっと数珠つなぎになるので、マクロにまとめてしまって、Event  Construct につないでおく。

f:id:hiyokosabrey:20191123194943p:plain

中身は、マテリアルを適用したImageパーツをVariables からGetノードで取り出して、Get Dynamic Material ノードをつないだら、ReturnValue ピンより Promote to Variable を選択すると、変数が作られる。

f:id:hiyokosabrey:20191122230120p:plain

それをひたすら並べていく。

f:id:hiyokosabrey:20191122230524p:plain

順番は適当でOK。

マテリアルはダイナミック化しないといじれないのと、マテリアルを触るたびに Get Dynamic Material するのは効率が悪そうなので、先に変数化しておく。

マテリアルの準備ができたところで、関数作成開始。

 

 

1. キャラの絵を変える setCharFaceTexture

f:id:hiyokosabrey:20191122224442p:plain

先に用意しておいたキャラ顔用のマテリアルインスタンスダイナミックより Set Texture Parameter Value ノードをつないで、Parameter Name を セットしたら、Value ピンを関数の Inputsピン につなぐ。

f:id:hiyokosabrey:20191122233531g:plain

 

 

2. 職業の名称を変える setJobName

f:id:hiyokosabrey:20191123083628p:plain

 もらったテキストをそのままセットするだけ。

 

 

3. 体力ゲージの長さを変える setGaugeHP

f:id:hiyokosabrey:20191123084046p:plain

そのままマテリアルに渡すだけだけど、ゲーム内で扱う体力の値は、受け渡しの扱い方を事前に決めておかないといけない。今回は比率でいいとのことなので 0.0 ~ 1.0 で扱う想定。で直接 0.0~1.0の範囲で値を受け取る仕様。

 

キャラクターのパラメータが成長するタイプの場合、体力の値は整数で、例えば 800 とか 15000 みたいな値で管理する方が都合がいいので、どこかのタイミングで変換してやる必要がある。

この関数内で変換する場合はこんな感じになる。

f:id:hiyokosabrey:20191123091126p:plain

その時点での最大値も一緒に受け取ることになる。

それと大事なのが、整数同士の割り算は結果が整数になるので、1.0までの結果はすべて 0 になってしまう。先にInt型からFloat型に変換してから割り算しないといけない。

 

UIのゲージ系表示で、長さが固定の場合、この計算は割と汎用的に行うので、マクロライブラリに追加してしまった方がいいかもしれない。マクロライブラリの管理担当と相談してOKが出たので追加してみる。

f:id:hiyokosabrey:20191123094831p:plain

 getRatio と命名

このマクロを先の体力ゲージに組み込む。

f:id:hiyokosabrey:20191123095014p:plain

完成。

 

4. スキルポイントゲージの長さを変える setGaugeSP

f:id:hiyokosabrey:20191123095230p:plain

体力ゲージと同じマクロでつなぐ。

完成。

 

 

5. スキルゲージ使用チャージの状況を変える setSkillChargeGauge

f:id:hiyokosabrey:20191123103354p:plain

これだけだとゲージの増減しかできない。

今回のデザインではゲージの見た目に溜まり具合が分かりにくいので、一緒にテキストも表示するようにしている。

f:id:hiyokosabrey:20191123104637p:plain

0.0~1.0の値に100を掛け算するとパーセンテージになるのでそれを FormatTextノードで「%」記号を付けて書きだす。

f:id:hiyokosabrey:20191123105030p:plain

FormatTextノードは結構柔軟に数値を取り込んでくれる(テキストに変換してくれる)ので便利だけど、桁のコントロールが必要な場合は、間にキャストノードを挟むといい。ToTextノードを展開すると以下のような設定ができるようになる。

f:id:hiyokosabrey:20191123120353p:plain

f:id:hiyokosabrey:20191123121131p:plain

チャージ量を表すとき、四捨五入や切り上げをしてしまうと、99.9% なのに 100%と表示されてクレームの元になるので、不都合な期待感を持たれないように切り捨てる。

上の画像のように設定すると、 1~100の整数しか表示されなくなる。

 

完成。

 

 

 

6. スキルのアイコンを指定したものに変える setSkillIconTexture

f:id:hiyokosabrey:20191123125004p:plain

スキルのID番号を Float に変換してパラメータとして渡すだけ。

完成。

 

 

7. キャラを使用できるまでのタイマーを指定した数字に変える setWaitTimerCount

f:id:hiyokosabrey:20191123134208p:plain

ひとまず直接パーセンテージの値で受け取ることにする。

小数点以下の桁数はデザインの都合で1桁に決めたので、この関数内で整える。

 

見た目にこだわって、小数部分の文字サイズを変えてしまったので、操作対象のTextBlockが2つに分かれることになった。

f:id:hiyokosabrey:20191123134410p:plain

整数部分は、Floorで小数部を切り捨てるだけ。

小数部は、まずFrac で整数部を捨てた後、欲しい桁数×10倍 して小数点を移動し、Floorで小数部分を切り捨てれば完了。

limesode.hatenablog.com

 

 

8.キャラの絵を待機中の見た目に変更する setCharWait

f:id:hiyokosabrey:20191124145844p:plain
 

 

9.キャラの絵を満タン時の見た目に変更する setCharReady

f:id:hiyokosabrey:20191124145823p:plain

 

 

10.スキルアイコンとゲージをチャージ中の見た目に変更する setSkillUseWait

f:id:hiyokosabrey:20191124141120p:plain

 

 

11.スキルアイコンとゲージを満タン時の見た目に変更する setSkillUseReady

f:id:hiyokosabrey:20191124141145p:plain


 

 

レイアウトしてみる

これで一通りの表示をコンとロールできるようになったので、画面に仮組みしてみる。

新しくレイアウト用のWidgetを作って、キャンバスにUser Createからドラッグ&ドロップして並べる。

f:id:hiyokosabrey:20191123192805p:plain

ドラッグするときのコツは、直接キャンバスにドロップすること。この時に中身のサイズを計算しくれる。

ヒエラルキーパネルにドロップすると、Widgetのサイズ情報がリセットされる。

f:id:hiyokosabrey:20191123194129p:plain

Size To Content にチェックを付ければいいだけの話なのだけれど・・・

f:id:hiyokosabrey:20191123195434p:plain

特に問題ではないんだけど手数が減るに越したことはない。

 

並べるときに、Anchors の設定を Bottom Centerにする。

f:id:hiyokosabrey:20191123195931p:plain

あわせて、並べたWidgetAligment X を 0.5 にすると中央揃えのパーツはものすごく並べやすくなる。理由は、画面中央のX座標が0になるから。

右側か左側を並べたら、片方は符号を逆にするだけでシンメトリーになる。

f:id:hiyokosabrey:20191123211044p:plain

 

  キャンバスに並べ終えたら、左から0~3の順でリネームしておく。

f:id:hiyokosabrey:20191123211435p:plain

 

グラフモードに切り替えたら変数を新しく追加する。→①

f:id:hiyokosabrey:20191123211907p:plain

Variable Type に先ほどキャンバスに並べたWidgetと同じ名前があるので、それを選択。→②

配列型に切り替え。→③

適当にリネーム。 →④

 

この配列にキャンバスに配置したWidgetをセットして利用する。

f:id:hiyokosabrey:20191123213318p:plain

こうしておくことで、ForLoopなどでまとめて処理できるようになるし、各Widgetを番号(0~3の整数)で扱うことができるので、なにかと便利になる。

 

再生するために、テスト用にレベルブループリントからViewportに書き出してみる。

CreateWidgetノードに、レイアウト用Widgetをセット。

f:id:hiyokosabrey:20191123212840p:plain

 

f:id:hiyokosabrey:20191123213035j:plain

キャンバスに並べたまんま。

関数のテストを兼ねていろいろ値を入れてみよう。

 

 

関数の動作テスト

レベルブループリントは閉じて、レイアウト用のWidgetを開く。

まずテスト用の関数を用意。関数のグラフを開いたら、

Inputsにキャンバスに配置したWidgetを探して追加。

f:id:hiyokosabrey:20191123214111p:plain

入力ピンからドラッグして call で検索すると頑張って準備した関数名がずらっと出てくる。(※エディタの言語をEnglishにしている場合)

f:id:hiyokosabrey:20191123214410p:plain

関数をいくつか呼び出して、ランダムな値でも入れてみることにする。

f:id:hiyokosabrey:20191123215210p:plain

とりあえずゲージ3種とタイマー。関数名は適当に TestParam と命名

 

EventGraphに戻ってつなぐ。

f:id:hiyokosabrey:20191123215356p:plain

これで再生してみる。

f:id:hiyokosabrey:20191123215541j:plain

配列の0番を関数に渡したので、左端のものだけ変化した。

あとは名前やらテクスチャやらも試してみよう。

さっきのテスト用の関数の中に追加。

f:id:hiyokosabrey:20191123215936p:plain

再生。

f:id:hiyokosabrey:20191123220049j:plain

うまくいってる様子。

 

この状態でも機能的にはかなり実装できた。

あと残っているのは重要な「イベント」。

 

 

イベント

イベントの発生には「条件」が付くのが基本だ。「条件」は銃で言うところの「トリガー」に相当するもので、条件が満たされた瞬間にトリガーが引かれ弾が飛び出す。飛び出した弾が「活動中のイベント」になって、次に何かに当たると当たったものによってリアクションの特定のイベントが発生する。そうやってイベントがドミノ倒しのように次のイベントを起こしていく。それが「イベントドリブン」イベント駆動ってやつだ。常に全体を見張っていて起こった事象を解析し、次の行動を確定する、というのに比べると、状況に応じて必要なイベントのみが処理されていくので無駄が少ない。

 

まずそのトリガーとなる要素を仕込む。

キャラ用のWidgetを開いて、キャンバスに Buttonパーツを重ねる。

f:id:hiyokosabrey:20191124002730p:plain

名前に Action と SkillUse を付けた。

個人的に推奨しているのが、名前の先頭にUMGのパーツ名をそのまま残しておくというルール。そうすることで同じ名称が使えるし、そのままグループだということも分かりやすくできる。

f:id:hiyokosabrey:20191124002546p:plain

見た目だけを非表示にしたいので、カラーを透明にする。

f:id:hiyokosabrey:20191124002853p:plain

f:id:hiyokosabrey:20191124002936p:plain

見た目より少し大きくカバーするようにしている。

ButtonパーツのDetailsタブにある緑色のイベント追加ボタンから On Pressed のイベントを追加する。触ってみて操作事故が起こるようだったら On Click に変えるといい。

f:id:hiyokosabrey:20191124003324p:plain

On Pressed は触れた瞬間にトリガーされて、On Clicked は一度触れ後、離れた瞬間にトリガーされる。押してから間違いに気づいた時、キャンセルできるかできないかの違い。

+ボタンをクリックすると、エディタは EventGraph に飛ばされて、一度イベントノードを作ると、次回から  +  が  View  に変わっている。このあたりからもエディタの優しさというか丁寧な作りを感じる。

 

f:id:hiyokosabrey:20191124125437p:plain

それぞれのボタンをクリックした時のイベント処理用のノードが置かれるので、ここにイベントディスパッチャー(イベントを起こすもの)をつなげる。

 

イベントディスパッチャーは、MyBlueprintタブの下の方で追加できる。

f:id:hiyokosabrey:20191124125809p:plain

これを先のイベントに Call で取り出してつなぐ。

f:id:hiyokosabrey:20191124131816p:plain

封筒のアイコンがつく。

f:id:hiyokosabrey:20191124131829p:plain2つのイベントにつないだら

 

f:id:hiyokosabrey:20191124132048p:plain

クリックされたら、この赤いイベントが呼び出され、さらにイベントディスパッチャーが通知イベントを起こします。この時点で通知先はまだ未定。

これでコンパイルして保存したらひとまず完成。

 

レイアウトWidgetの方に移って、イベントディスパッチャーを受け取る用意をする。

f:id:hiyokosabrey:20191124132739p:plain

テストで、クリック受け取ったら Print String ノードで画面に表示するようにしてみた。

この バインドノードが対象Widgetにある イベントディスパッチャーと紐づけ(Bind)てくれる。

バインドすることで、イベントディスパッチャーと通知先がつながるので、別々のWidgetでも通信ができるようになる。親のWidgetから子のWidgetへのアクセスはできるけど、子から親へのアクセスはできない。それを特別なルートでつなぐことができるのがこのイベントディスパッチャーとバインドと使った仕組み。

 

これで再生してみる。

f:id:hiyokosabrey:20191124134507j:plain

ちゃんと反応してくれている。

これで受け取った時に待機中の見た目にすればさらに雰囲気が出そう。

まず満タン状態にするために、テスト用関数の最後に、満タン状態にする関数をつなぐ。

f:id:hiyokosabrey:20191124135200p:plain

これで再生した時に、待機中のタイマーが消えていれば成功。

キャラのWidgetの方で初期状態を非表示にしておけばいいのだけど、関数のテストも兼ねてつないでみた。

 

クリックした時に待機状態にしたいので、Print String を入れ替える。

f:id:hiyokosabrey:20191124135551p:plain

これで再生してみると。

f:id:hiyokosabrey:20191124135909g:plain

スキルも同じようにしてみる。

f:id:hiyokosabrey:20191124141417g:plain

 

他のキャラにもバインドすれば同じように動作する。

普通につなぐとちょっと冗長(だら~っとすること)になってしまう。

f:id:hiyokosabrey:20191124142521p:plain

一応これで動くけどスマートじゃない感じ。

 

とりあえずテスト用関数を少しいじって、キャラ顔のテクスチャとスキルID、職業名を外から渡せるようにしてみる。

f:id:hiyokosabrey:20191124150605p:plain

 

これでテクスチャとかを個別にセットして再生してみる。

f:id:hiyokosabrey:20191124151049g:plain


一応完成。

f:id:hiyokosabrey:20191124151549j:plain

 

この辺からは、キャラクターのステータスを管理する仕組みと連動するので、ひとまずUIとして仕込めるのはこの辺までにしようと思います。バインドのところがスマートじゃないので、次回《番外編》を書こうと思います。

 

f:id:hiyokosabrey:20191124152117j:plain

ではでは

ステキなキャラ顔表示ライフを!