この記事は
Unreal Engine 4 (UE4) Advent Calendar 2015 24日目の記事です。
-------------------------------------------------------------------------------
1.はじめに
「UE4使ってみたけどUIってどう作るんだろう」「サンプルあるけどちょっと足りないなぁ」
そんなことからこの記事を書いてみました。
UE4にはUIを簡単に構築できる
UMGという機能があります。
そこで今回はUMGの機能、UMGを使用したUIの実装に関してざっくばらんに紹介します。
今回はサンプルとして某ゲームのUIを作成してみました。
こんな感じ↓のUIを作ってみます。
(FinalFantasy7です。以降、FF7のキーワードが出てきます。未プレイの方はごめんなさい...)
-------------------------------------------------------------------------------
2.ワークフロー
実装に入る前にUI作成のワークフローについて少し。私がUIを実装する時は以下のような手順で作成します。この方法が正しいとも限りませんし、もっと効率の良い方法があるかもしれませんので、そこら辺はご了承下さいませ。
----------------------------------------------------------------
【UI実装の手順】
①:大枠を作りアタリをつける
↓
②:パーツ化する部分を決める
↓
③:②でパーツ化した部分を細分化、実装
↓
④:③で生成したWidgetを組み合わせて②を構築
↓
⑤:④で生成したWidgetを組み合わせて①を構築
↓
⑥:ロジックへの接続
----------------------------------------------------------------
①:大枠を作りアタリをつける
全体のイメージを掴むため、パレット内のオプションを使って適当に配置していきます。
この段階ではアンカー(Widgetの基準位置)や細かいスケールは気にせず気楽に配置します。
作業自体はアーティストなどの手を要さずにでき、下手に絵コンテなどを作成するよりもスピードが速く効率的かと思います。
②:パーツ化する部分を決める
①で作成した全体概要を元にパーツ化する部分を決めます(構想だけ)。
色互いに枠で囲まれている部分がパーツ化する部分です。
③:②でパーツ化した部分を細分化
②でパーツ化した箇所を、緑枠のようにさらに細分化します(構想だけ)。
ここでは他のUIで使い回すことを意識して細分化します。
例えばHPのテキストやリミットゲージなどは、バトルメニュー以外にもフィールドメニュー等で使い回すので、ここでは細分化の対象としておきます。
④:③で生成したWidgetを組み合わせて②を構築
⑤:④で生成したWidgetを組み合わせて①を構築
パーツ化したWidgetを組み合わせて親Widgetを作成します。
また親側から子に対する制御、参照部を作成します。
↓
⑥:ロジックへの接続
UIを制御するきっかけとなる処理(トリガイベント、キー入力など)を作成します。
ウォーターフォールモデル開発と同じような手順ですが、
UI自身の役割、機能を明確にしたり、作業を分業化するのに向いているかと思います。
-------------------------------------------------------------------------------
3.実装
3.1.パーツ部の実装
3.1.1.Timeゲージ
既に実装手順の①~③は上の方で作成したので早速パーツ部分を実装してみます。
ここではActiveTimeBattleの肝である、プレイヤーの時間を管理するTimeゲージを実装します。
ゲージは待機中、行動待ち、行動中の3色が存在し、時間と共に増加します。
今回は背景のテクスチャ、ゲージ用マテリアルで構築してみました。
①背景テクスチャ
アンカーをX:0.5、Y:0.5に設定し、キャンバスの中央にテクスチャを配置しています。
サイズはViewportサイズ基準で適当な数値を設定します。
Imageにテクスチャを指定し、テクスチャ設定を"UI"に設定しておきます。
②ゲージ部マテリアル
ゲージ部は動的に変化させる必要があるため、マテリアルを設定します。
サイズ、アンカーは①と同様な設定、表示上の微調整が必要な部分はMarginで補正します。Marginの内容に関しては以下のサイトで詳しく解説されており、UI設計でテクスチャ、マテリアルを頻繁に使い回す場合など良く使います。
[UE4] 枠線の太さはそのままで拡大縮小できるUIの作り方 (株式会社ヒストリア様 ブログ)
ゲージ部分のマテリアルは上記のように(ContentExampleのサンプルを流用)作成し、
ゲージの割合をScalarParameter、ゲージのActive/Deactiveな部分のカラーをVectorParameterで外部から指定できるようにしています。
さらにUIでマテリアルを使用する場合はマテリアル属性を変更しておく必要があります。
ここまでがデザイナ部分の設定となります。
次にグラフ部分の実装を行います。
パーツ化したWidgetの機能はそのWidget内で機能を完結させることを目的とし、ゲージ部に必要な情報を変数として用意します。更新フラグ、ゲージ割合、状態、カラー情報などを一通り用意し、Construct(Widget生成時に呼ばれる箇所)でゲージ部分のマテリアルを生成します。
次にゲージ割合を更新する関数(UpdateGauge)を作成します。
ゲージ割合を更新したタイミングでマテリアルをWidgetに反映し、さらにステートが変化したら色を更新する流れとなっています。
現在の状態取得
状態に応じた色の更新
これでゲージの割合とゲージの色更新部分はできました。
あとは任意のタイミング(プレイヤのターンが回ってきた時に)で上記の関数を呼び出せば、ゲージを水色→黄色→橙色に更新することができます。バトルでは複数プレイヤのTimeゲージが100%になることがあるため、ゲージをActiveにするタイミングはプレイヤの時間を管理するクラスから一番早くATBバーが貯まったプレイヤに対してSetActive関数にアクセスしてActive状態とします。
3.1.2.名前テキスト
次に名前のテキストに関する実装を行います。
名前も同様に状態によってテキストの色が変わる動作となり、プレイヤに行動が回ってくると1番目(白色)と2番目(灰色)のブリンク表示となります。
上記の動作から、名前テキスト用Widgetで変更が必要なのは「テキスト内容」と「テキストColor」となります。これらはBind機能を使用して更新します。
プロパティのバインディング(公式ドキュメント)
今回のケースでは変数Bindと関数Bindで分けて使用していますが、変数BindはWidget内に同型の変数が存在すればアクセスできます(候補として出てくる)。本ケースでは変数"Text"に"グレーマン"とSetすることでテキスト内容に反映することができます。
また、関数Bindに関しては同型の出力を持ち、かつ入力が存在しない関数であればアクセスできます。Widget更新に関しては、Bindアクセス以外にも、上記Timeゲージで使用したイベント駆動アクセスがありますが、処理負荷などの面で使い分けを行う必要があります。詳細は後述で触れます。
次にテキストColor部分の実装です。
はじめにfloat型変数"HP Rate"で残HPの割合をチェックしており、残HPが0の場合はColor:Red、被Active状態ではColor:White、Active状態ではタイマとして用意している変数の値に応じてColor:White、Color:Grayを設定しています。ここでColor情報はPure関数から取得していますが、テキストのカラーはシステム共通だったりすることを考慮して(他のテキストでColor情報を設定する際にそれぞれでRGBを指定するのが面倒なので共通化してしまいました...)BlueprintFunctionLibrary経由でMaterialParameterCollectionから取得しています。
あとは準備した変数に対して適切な値を設定してあげれば名前テキストの実装は完了となります。
3.2.パーツを組み合わせ
3.1.でパーツ部分をいそいそと作ったら、ワークフローを逆になぞるようにWidgetを組み合わせて集約していきます。パーツ化したWidgetは他のWidgetで使用することができ、親子関係を作ることができます。
上記はパーツ化したTimeゲージや名前テキストを組み合わせたWidgetです。
以下のように1人のプレイヤーの情報として纏めてしまい、子Widget側では自分の機能だけを果たすようにしてしまいます。
さらにパーツ化したWidgetを組み合わせると以下のように全体像が見えるようになりました。
以上、UIの作成に関する一例を挙げてみました。
これでUIの大枠が完成しました。
(その2)に続く→