みつまめ杏仁

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

UMGで ルビを振ってみる

f:id:hiyokosabrey:20180517231335j:plain

UMGでルビを振ってみようと思って試してみました。

途中諦めようかと思ったけど、なんとか形にすることができたので、メモっておきます。

今回日本語フォントとして、たぬき油性マジックという書体を使ってます。

 

仕組みとしては、まずルビ付きの文字をまず括弧的なもので分けたテキストを用意。

ここは人力。

それを分解してテキストブロックにしてUMGで表示します。

そのあと、ルビを置く場所を計算しながら置いていきます。

例えば、

f:id:hiyokosabrey:20180518213959p:plain

といった具合です。

 

で、UMGでTextBlockを並べるのですが、入れ物として2種類のパネルを使います。

f:id:hiyokosabrey:20180517235253p:plain

f:id:hiyokosabrey:20180518010435p:plain

CanvasPanel の方はルビ専用で、自由な場所に置くためです。一方の HorizontalBox は楽して左詰めするためです。

Size To Contentのチェックを付けていると、上図のようにバウンディングボックス(緑の枠)が小さくなりますが、ルビと本文の距離はここで調節します。

 

ブループリントからいじるので、 Is Variable のチェックを付けておきます。

キャンバスは以上です。

 

まず文字列を解析する関数を用意します。

この関数には、String型の入力ピンを一つと、本文とルビを配列で返すピンを追加します。

f:id:hiyokosabrey:20180519125150p:plain

Local変数も追加します。下図は、関数のピン設定とローカル変数。

f:id:hiyokosabrey:20180518011911p:plain

そして今回のキモとなる文字列分割ノード。

f:id:hiyokosabrey:20180519124901p:plain

まず 区切り文字=デリミタに設定した半角の { で配列に分解します。

{ から始まる文章が来るかもしれないので、 Cull Empty Srings のチェックは外しておきます。

 

このノードを通った分割後の文字列はこんな状態。デリミタは消滅します。

f:id:hiyokosabrey:20180518013407p:plain

 

ブランチノードで、デリミタが存在するか確認して分岐します。配列の数を調べれば分割されたかどうか判明します。

 

デリミタが無い=ルビが無い 場合、ルビに関する処理はしないので以下のようにします。

f:id:hiyokosabrey:20180518013930p:plain

分割があった場合は、 } が含まれるので、今度は Splitノードを使ってルビを分離します。

f:id:hiyokosabrey:20180519093329p:plain

わりとややこしい流れになったので、文字列が処理されていくイメージを図で説明するとこんな感じになります。

 

f:id:hiyokosabrey:20180519093043p:plain

 

Index に +1 して set Array Elem しているのは、 Insert ノードを使った直後はこうなっているからです。

f:id:hiyokosabrey:20180518230212p:plain

まだForEachLoopの Index は 1 のままなので、+1 しているという訳です。

 

で、最終的に2つの配列が整います。

f:id:hiyokosabrey:20180518230342p:plain

 

関数は以上です。

 

 

EventGraphに戻って、変数を一通り準備します。

f:id:hiyokosabrey:20180519095227p:plain

一番下の Stringは、Expose on Spawn にチェックを付けておきます。

f:id:hiyokosabrey:20180519123358p:plain

 

書体設定用の変数は、Slate Font Infoという変数タイプです。

一度コンパイルしてやるとDefaultValueからフォントやサイズが設定できるようになります。

f:id:hiyokosabrey:20180519094542p:plain

フォントの設定は、後からノードでも指定できるんですが、あらかじめ書体やサイズなんかが決まっていて途中で変更することが無い場合は、こうして変数の初期値として持たせておくとノードをつなぐときスッキリできるのでおススメです。

 

変数が用意できたら、文字を並べていくところを作っていきます。

f:id:hiyokosabrey:20180519104100p:plain

 用意しておいた関数から出てきた配列型の文字列を、準備した配列変数に保存します。

それを基にForEachLoopで順番に処理します。

上の方にあるConstruct Text というノードはそのまま探しても出てきません。

探すときはコレ。

f:id:hiyokosabrey:20180519104610p:plain

たいていのものはこのノードで実体化できるので、大変便利です。

Outerのところは、パネルの子供にすることが決まっているので、親になるHorizontalBoxをつないでいます。特に親がいない場合はSelfノードで大丈夫みたいです。

Classは、TextBlock をセットします。するとReturn Valueピンからは UMGの生TexBlockが生成されてくるので、いろいろ設定をしてやります。

これでルビを除いた本文だけが並べられて表示できるようになります。

ループ処理が終わったら、 Force Layout Prepass ノードを入れます。

f:id:hiyokosabrey:20180519105851p:plain

これは、TextBockの表示サイズを正確に取得するためです。

サイズが固定されてなくて、Size to Content にチェックがついているようなTextBlockやCanvasなどのWidgetパーツは、WidgetレンダリングされるタイミングとWidgetブループリントが処理されるタイミングがかみ合わないことがあって、サイズ取得できないことが多いです。

 

Widgetブループリントが、描画担当にテキストを渡して

Wブ「このテキスト表示してよ」

描画担当「分かった~」

Wブ「で、サイズは?」

描画担当「これくらい?」

Wブ「ほんとに?  ちょちょ も1回 Pre-passで確認してよ」

 

 ってことだろうと勝手に想像してます。

 

つぎにルビの表示処理です。

そのまえに、本文のTextBlockのサイズをチェックして加算するマクロを用意します。

f:id:hiyokosabrey:20180519113404p:plain

単純にTextBlockの幅を自身に加算してRubyPosition変数を更新していきますが、ルビで必要なのは、ルビを振る対象のTextBlockの幅を1/2したサイズだけが必要です。OffsetCenter変数にはそのまま入れるので常に上書きすることになります。

 

グラフに戻って続きを作ります。

今度は、ルビ用の配列変数をForEachLoopで処理していきます。

マクロで、本文のTextBlockの幅を調べて加算しつつ、ルビがあるかどうかをチェックします。

f:id:hiyokosabrey:20180519113831p:plain

ルビ用の配列に空(Null)を入れていたのはこのためです。ルビがあろうとなかろうと本文は並べられます。どのTextBlockがルビ振り対象だったかを覚えておくためには単にに別の配列を用意して同じ順番にルビを入れておけばいいよね?っていう発想です。

常に座標だけは計算しておきたいので、マクロをブランチノードの前に置いています。

ルビが見つかったら、本文と同じ要領でTextBlockを生成して、フォントの設定をします。

文字のレイアウト設定なんかもあるのでちょっと大きくなってます。

f:id:hiyokosabrey:20180519114904p:plain

最後のSet Positionノードで、ルビの位置がセットされます。

 

仕上げに、EventTickに、あのForceLayoutPrepassノードをつないでおきます。

f:id:hiyokosabrey:20180519115159p:plain

ちょっとしつこい感じですが、いろいろ試してみてTickでもやった方がいい結果になったのでつなぐことにしました。毎フレーム処理されるのは負荷が高いので、本文の表示が終わったタイミングで処理が走り始めるようにしています。

なぜか、ルビの表示処理が終わって、isActive を false にすると、ルビの位置がずれるのです。ずっとTickが走り続けるのが気になるのですが、今のところ他の解決策が思いついていないので、情報をお持ちの方はネットに公開していただけると助かります。

 

これでルビ付きテキスト表示のWidgetは完成です。

 

複数行を処理してルビ付きテキスト表示するためのWidgetを用意します。

キャンバスの適当な位置に VerticalBoxパネルを配置します。

f:id:hiyokosabrey:20180519120727p:plain

Size To Content と Is Variable にチェックを付けています。

配列変数を一つだけ用意します。受け取った文字列を配列にして保持するためのものです。

f:id:hiyokosabrey:20180519120936p:plain

String型なのにTextという名前を付けるのためらったのですが、大本の「文章」が渡されてくることを考えて、あえてTextArrayとしました。アイコンの色と形で分かるのがビジュアルスクリプトの素晴らしいとこだと思うので、混乱は無い、と信じたい・・・

 

で、受け取ったテキストは以下のような状態で受け取ります。

f:id:hiyokosabrey:20180519121656p:plain

改行位置は赤い矢印 の箇所。

うしろの方のしずかな空で、いきなり音がしましたので
シグナレスは{急|いそ}いでそっちをふり{向|む}きました。
ずうっと{積|つ}まれた黒い{枕木|まくらぎ}の向こうに、あの{立派|りっぱ}な{本線|ほんせん}のシグナル{柱|ばしら}が、
今はるかの南から、かがやく白けむりをあげてやって来る{列車|れっしゃ}を{迎|むか}えるために、
その上の{硬|かた}い{腕|うで}を下げたところでした。

 

宮沢賢治の「シグナルとシグナレス」より。

青空文庫からコピペさせていただきました。

 

この改行を分解して配列にします。

その関数が以下。再び Parse into Arrayノードの出番です。

f:id:hiyokosabrey:20180519122255p:plain

最後のSet Padding は、行間の調整用です。

下は Construct Object from Class ノードです。作っておいたルビ付きテキストWidgetをセットします。アセットも生成できるので、Create Widget とほぼ同じ。

f:id:hiyokosabrey:20180519122735p:plain

 

以上でWidgetは完成です。

テスト表示用にレベルブループリントを編集します。

f:id:hiyokosabrey:20180519123705p:plain

 

表示してみると、冒頭のキャプチャになりました。

いろいろ試してみました。

f:id:hiyokosabrey:20180519130912p:plain

フォントにいいのが無かったので、まったく迫力出ないですね。

再び青空文庫より。

f:id:hiyokosabrey:20180519135212j:plain

夢野久作の「ドグラ・マグラ」より。

もうノベルゲームが完成した感があります。

 

なんとかルビが付くようにできました。

もっといい方法があるぜよ、という方がおられればぜひご教授いただければ嬉しいです。

 

ではでは 今回はこの辺で

ステキなルビ振りライフを!

 

 

 

[3D]シンプルなリストメニュー作ってみる

前回のタブっぽい何かに、リストメニューっぽい何かを追加してみます。

f:id:hiyokosabrey:20180505224715j:plain

背景のマテリアルにPARAGONのアセット使わせていただきました。

 

その前に前回のマテリアルで、大事な設定を見つけました。

UI 表示では フォグの影響を受ける必要はないので、Apply Fogging のチェックを外してみました。

f:id:hiyokosabrey:20180505112157p:plain

すると、Intructions(命令)の数が減ったのです!

f:id:hiyokosabrey:20180505112803p:plain

f:id:hiyokosabrey:20180505112814p:plain

頂点シェーダの処理が約1/2、TextureSamplersの数も1/4になったので、これは効果アリですね。次回から確実に外していこう。

 

では、リストメニュー用のスタティックメッシュを用意します。

Blenderで↓のようなメッシュを作りました。

f:id:hiyokosabrey:20180505113546p:plain

下にある黒っぽいのはドロップシャドウ用のメッシュです。2面のポリゴンで1つのオブジェクトになっていて、こうことができるのがスプライトにない強みですね。作るときは1枚だけ作って複製し、ずらして統合します。影のカラーを付けたいので頂点カラーを付けています。

 

ちなみに作業用のテクスチャは以下。等間隔に並べます。

f:id:hiyokosabrey:20180505123600p:plain

この色分けはUV範囲を分かりやすくするためにレイヤーで色を載せています。この色分けに沿ってUVの頂点をきっちり当てます。

f:id:hiyokosabrey:20180505123854p:plain

エンジンにインポートする際は、グレースケールにして、TGA形式にします。

f:id:hiyokosabrey:20180505123615p:plain

 

メッシュはFBXでエクスポートします。流れは前回の記事と同じですが、頂点カラーを有効にする必要があります。まずは Import Settings でやる場合は、以下の場所にあります。

f:id:hiyokosabrey:20180505124833p:plain

 

インポートした後に有効にすることもできます。その場合は StaticMeshエディターの右のDetailsタブの中にあります。

f:id:hiyokosabrey:20180505125110p:plain

変更したら、Assetメニューから Remport(再読み込み)すれば反映されます。

f:id:hiyokosabrey:20180505125321p:plain

 

テクスチャインポートしたら、マテリアルを作成します。

f:id:hiyokosabrey:20180505132010p:plain

 

頂点カラーを使うには 専用のノードが用意されています。そのまま Emissive Color に渡してもいいのですが、ブループリントから色味をいじりたいので、MultiplyノードでVectorParameterノードを掛けています。

f:id:hiyokosabrey:20180505130420p:plain

 

リストの文字は、UVの位置をずらしてバリエーションを出します。

f:id:hiyokosabrey:20180505132057p:plain

今回移動するのは縦方向、Vの値だけが変化すればいいので、Uの値はそのままにします。

ちなみに Append は合成、Add は加算です。

A と B を Append すると、 (A, B) になって

A と B を Add すると、 A + B になります。

 

白いラインが全部一緒なので、慣れないと分かりにくいのですが、上の場合、

TexCoordから出てるのが、(U, V) の Flort2 または Vector2 とよばれる型。

左端の2つのノードは 単品のFloat型で、これを Append でくっつけて、

(0, OffsetV) にして、Add ノードで、(U, V) に加算しています。なので、

(0, 0.5) + (0, 0.25) だと (0, 0.75) になるのです。この単品の float が何本になってるかをノードの前後で把握することのが、マテリアル攻略の助けになります。

ちなみに下の例では、エラーにはなりませんが・・・

f:id:hiyokosabrey:20180505132710p:plain

(0, 0) に対して 単品の float を足すので、OffsetV = 0.25 だとしたら、

(0.25, 0.25) になります。これではUVが斜めに移動することになります。

 

マテリアルができたので、次にマテリアルインスタンスを作ります。

 マテリアルのアセットアイコンの上で右クリックしてコンテキストメニューから選択します。一番上にあります。

f:id:hiyokosabrey:20180505225010p:plain

マテリアルインスタンスにすると、仕込んでおいたパラメータのみ触ることができるようになります。(チェックボックスにチェックを付ける必要があります)

f:id:hiyokosabrey:20180505225433p:plain

文字を変更するのはUV値のVの方なので、パラメータ ”OffsetV” の値を変更します。

今回は48px ÷ 512px = 0.09375 が間隔なので、パラメータは以下のようになります。

f:id:hiyokosabrey:20180505230933p:plain

 

テクスチャに並べておいたテキスト分のマテリアルインスタンスを用意します。

いまのところコンテンツブラウザは以下のような状態。

f:id:hiyokosabrey:20180505231243p:plain

 等間隔に並んでいるので計算させた方がよさそうに見えますが、ゲーム開発においてメニュー項目なんてのは変更されるのが常です。さらにイベント用ROMなど特殊な状況のパッケージを作る際にも意図的に変更することがあります。このようなアセット構造にしておくことで、プログラマーとデザイナーとで分業しやすい状態にできるのでオススメです。

 

ブループリントアクターを用意します。

f:id:hiyokosabrey:20180506170156p:plain

StaticMesh とChildActor をAdd Componentボタンから追加します。

f:id:hiyokosabrey:20180506031559p:plain

追加しただけだと空っぽなので、Static Meshには さきほどインポートしたMeshアセットと対になるマテリアルインスタンスをセットします。

f:id:hiyokosabrey:20180506102851p:plain

 

最後の Child Actorコンポーネント には、前回の記事で作ったブループリントをセットします。

f:id:hiyokosabrey:20180506103551p:plain

 

Child Actorコンポーネントは、そのままだと中身にアクセスできないのでConstruction Script 内でキャストして変数化しておきます。

f:id:hiyokosabrey:20180506102633p:plain

(なんかちょっと不思議な感じ、間違ってるのかな・・・)

続きを組む前に、関数を2つ用意。

 

 見た目をデフォルトにする関数と、

f:id:hiyokosabrey:20180506111409p:plain

f:id:hiyokosabrey:20180506111154p:plain

 

見た目をフォーカス状態にする関数。

f:id:hiyokosabrey:20180506111421p:plain

f:id:hiyokosabrey:20180506111204p:plain

 

ConstructionScript 内で表示位置と状態のセッティングは済ませておきたいので、

StaticMeshComponentを配列変数にして、そこから ForEachLoop でいろいろセット。

f:id:hiyokosabrey:20180506114230p:plain

ループ処理の前後どちらでも問題ないと思うけど(上図では後)、配列に仕込んだ数を変数に持たせておきます。

 

準備ができてきたので、前回作ったタブっぽいウィンドウのブループリントを再び編集します。

f:id:hiyokosabrey:20180506170306p:plain

イベントディスパッチャーを追加します。

f:id:hiyokosabrey:20180506164617p:plain

作ったイベントディスパッチャーは、アニメーションの終了を通知するためのもので、TimeLineノードのCompleteピンにつなぎます。

f:id:hiyokosabrey:20180506164853p:plain

 これでこのブループリントは編集終了。

 

次はこのイベントディスパッチャーをバインドしてやります。

 

再び今回のBP。

f:id:hiyokosabrey:20180506170128p:plain

 

f:id:hiyokosabrey:20180506171016p:plain

 これで、ウィンドウの出現アニメーションが終わるのを待つことができます。

出現が完了したら、カスタムイベントで受け取って、リストメニューを表示する、という流れです。ここでリストのフォーカス位置を管理するための変数 int型 をひとつ用意しています。上図の FocusIndex。

 

右下の部分は、このあと何度か登場するので、関数にしてしまいます。

f:id:hiyokosabrey:20180506190940p:plain

まとめて選択しておいて、右クリック > Collapse to Function を選びます。

できた関数ノードを編集して、Pure型にしてみます。

f:id:hiyokosabrey:20180506191422p:plain

ノードが変化します。

f:id:hiyokosabrey:20180506191616p:plain

 今フォーカスされてるやつをGetするだけの関数だけど、こうしておくことで、ノードもスッキリして、名前で何をしてくれるかわかるし、関数の中にチェックの仕組みも入れやすくなります。

例えば下の例は StaticMeshComponentの配列から正しく取り出せるかチェックする場合。

f:id:hiyokosabrey:20180506211702p:plain

 

で、リストのフォーカスをくるくると切り替える仕組みをカスタムイベントで組みます。

f:id:hiyokosabrey:20180506231026p:plain

 このイベントの Inputs(引数)は int型で、+1-1 を受け取ります。

 

 ブループリントはこれで一応完成です。

 

さっそくレベルブループリントからテストしてみます。

f:id:hiyokosabrey:20180506213255p:plain

左の Set View Target with Blend ノードは、任意のカメラに切り替えるときに使います。Spawn Actor from Class ノードを使ってActorブループリントをシーンに呼び出します。

f:id:hiyokosabrey:20180506213641p:plain

キー入力でテストしてみたので、Inputノードは カーソルキーの ↑(Up)↓(Down)です。

再生してみると、

 

f:id:hiyokosabrey:20180506225458g:plain

GIFが重くて上げられなかったので2つに分けました。

f:id:hiyokosabrey:20180506225543g:plain

 

 うまく動いてくれました。

PostProcess の影響を受けるので、カラーのコントロールが難しいですが、UMGと大して変わらない印象です。UVアニメーションで凝ったことができるのと、アルファの透明部分をカットして描画負荷を軽くしたり、UVがレクト(長方形)じゃなくてもいので、テクスチャを節約できたり、頂点カラーが使えたりと、メッシュでUIパーツを作成できると、いろんな表現ができるのでとても楽しいです。

個人的に、お手軽さではUMGの方に軍配が上がりますけどね。

 

ではでは今回はこの辺で

ステキな[3D]UIライフを!

 

 

 

 

 

 

 

 

[3D]頂点移動でタブウィンドウ的な何かをつくる

 先日4/21のアンリアルフェスに参加してきました。あっという間の8時間で、アンリアルエンジンに関わってる人たちのお話をもっともっと聞いていたい、そんなイベントでした。残念ながら懇親会のチケットは速攻でSOLD OUT。横浜のフェスも行きたいけど遠いな~。

 

 で、今回は3Dメッシュでウィンドウっぽいものを作ってみます。

たまにはポリゴン使ってUI作ってみようかな~などと、思ってみたりしちゃったのでやってみました。まず用意するのはテクスチャとポリゴンメッシュ。メッシュはBlenderを使用しました。

 

まずテクスチャ。

f:id:hiyokosabrey:20180427001732p:plain

サイズは 256x128 今回アルファチャンネル無しのグレースケールテクスチャです。

VRAMの使用量を抑えて非圧縮にできるのでオススメです。

これに、UV範囲が分かるように色付けしてBlenderに持っていきます。

f:id:hiyokosabrey:20180427002033p:plain

 

平面を扱うので、Blenderの場合、作業する際にテンキーの[7]、[5]を押して、トップビューの平行投影にすると、 ペラポリゴンがきちんと平面で編集できます。出来上がりは↓のようになります。

f:id:hiyokosabrey:20180427002718p:plain

一応手順を簡単にメモっておきますね。

Planeメッシュを作成して、ざっくりと上図のように分割します。「ループカットとスライド」を使ってテキトーに割っていきます。

f:id:hiyokosabrey:20180427003942p:plain

このオブジェクトにマテリアルとテクスチャを追加します。そして「編集モード」に切り替えて「UV展開」したら、UVの頂点をテクスチャの色分けに合わせて移動させます。このときUVの頂点は「ピクセルに吸着」にチェックを付けておきます。

f:id:hiyokosabrey:20180427003109p:plain

UVの編集が終わったら、メッシュの頂点を整えます。ざっくりとピクセル基準でOK。モデルのサイズは後からスケールで調整できます。

色分けのピクセルに合わせるように頂点座標を編集しますが、「単位」の設定を確認します。

f:id:hiyokosabrey:20180427224405p:plain

プロジェクトによって、またカメラとの合わせ方によって変わるので、あくまでも参考程度にお願いします。

この設定の場合、1ピクセルを1mとして作っていきます。

f:id:hiyokosabrey:20180427224923p:plain

 ここで、欲しいウィンドウの横幅になるよう左右を引き延ばしておきます。

 

モデルができたら、FBX形式 で エクスポートします。

f:id:hiyokosabrey:20180427225354p:plain

 エクスポート設定は以下。

f:id:hiyokosabrey:20180428223617p:plain

ちょっと小さくて分かりにくいですが、上 は 『 -Yが上 』を選びます。

この設定はBlenderを終了しても覚えておいてくれないので、+ ボタンをクリックしてプリセットにしておくのをオススメします。

 

名前をつけて書き出したら、UE4のコンテンツブラウザにドラッグ&ドロップします。

このときちょっとだけ待ってあげてください。おそらく中身を解析してます。

f:id:hiyokosabrey:20180428104734g:plain

 

インポート設定のウィンドウがポップアップするので、確認しながら調整します。

基本的にデフォルト設定のままで大丈夫ですが、無用なデータが作られるのは避けたいので、チェックした方がいい個所を記しておきます。

f:id:hiyokosabrey:20180428111451p:plain

FBXに関して詳しいことは公式サイトをぜひ

Unreal Engine | FBX コンテンツ パイプライン

 

これで無事インポートできたら、テクスチャもインポートします。

インポートしたテクスチャからマテリアルを作成(Create Material)します。

テクスチャはグレースケールで作っています。

あと、もう一枚テクスチャを追加します。

UV座標をすこしカバーするように、赤と青で塗りつぶします。

f:id:hiyokosabrey:20180428113906p:plain

※分かりやすいようにオレンジのラインを重ねています。

赤は(255,0,0)青は(0,0,255)にします。

255 を使わないと計算のときに 1.0 にならないのでご注意を。

この単純な色ベタのテクスチャを 32bpp のフルサイズ で作るのはテクスチャメモリがもったいないので、解像度を下げます。この時、ニアレストネイバー を選択するとピクセルがボケません。できるだけ 1/2、1/4単位で縮小します。赤と青のピクセルも基本的に奇数は使わない方が無難です。これはテクスチャを作る場合は偶数を基本にした方がいいです。あくまでも面積的な話です。で実際に使ったのがこれ。

f:id:hiyokosabrey:20180428114908p:plain

64x32です。

これをマテリアルに追加するのですが、テクスチャのフィルタ設定を変更します。

2枚のテクスチャ設定を並べてみます。

f:id:hiyokosabrey:20180428115949p:plain

これをマテリアルで組んでいきます。

 

 マテリアルは、光源計算しないのと、半透明なので、

f:id:hiyokosabrey:20180428214009p:plain

全体図はこんな感じ。

f:id:hiyokosabrey:20180430144459p:plain

キーになるのは LocalPosition ノード。

f:id:hiyokosabrey:20180430144815p:plain

ここから頂点座標を取り出したものに、マスクテクスチャを使って値を作り、X軸とZ軸にそれぞれ足し算してやります。

緑のScalarParameterノードは、ブループリントからいじるためです。

f:id:hiyokosabrey:20180430144907p:plain

頂点をいじった状態を本来のオブジェクト位置に引き戻したいので 絶対ワールド位置 ノードを使います。この Absolute World Positionノード、 Absolute で検索しても出てこなくて、普通に World Position で並んでて取り出すとこのカタチになる。

f:id:hiyokosabrey:20180430145504p:plain

ネットの参考画像と合わなくてくじけそうになった。

 

 

マテリアルができたら、スタティックメッシュのアセットを開いてセットします。

f:id:hiyokosabrey:20180428214617j:plain

 

Actor型のブループリントを用意します。

f:id:hiyokosabrey:20180428214933p:plain

さっそく編集していきます。

まず、左上の緑のボタンから Static Mesh を追加します。

f:id:hiyokosabrey:20180428215252p:plain

追加したStaticMeshコンポーネントは、名前を変更できます。

追加できたら、右のDetailsタブから、作ったスタティックメッシュをセットします。

f:id:hiyokosabrey:20180428224323j:plain

 

続いて、EventGraphを編集します。

その前にConstruction Scriptで透明度のセットをしておきます。

f:id:hiyokosabrey:20180430150549p:plain

出現時は透明なんですが、最初の配置調整が大変なので、ここで強制的に 1.0 にします。マテリアルにセットしたパラメータ ”Opacity” に値を渡します。最後に準備ができたら 0.0 に戻します。

 

次に

EventGraphにカスタムノードを置いてつないでいきます。

f:id:hiyokosabrey:20180430151329p:plain

タイムラインノードの中身はこんな感じです。Float型が2つ。

f:id:hiyokosabrey:20180430151654p:plain

ウィンドウの高さ = Height は、固定の値にするのではなく、0.0 ~ 1.0 のアニメーションにします。こうしておくと、いろんな値を掛け算するだけで自由なサイズのアニメーションが作れます。

 

出現アニメーションができたのでテストしてみます。

スポーンされた想定で、EventBeginPlayノードから、上のカスタムイベントを呼び出すことにします。

f:id:hiyokosabrey:20180430152546p:plain

コンパイルして保存したら、シーンに適当に配置します。

再生しすると、

f:id:hiyokosabrey:20180430153630g:plain

いい感じになりました。

UMGを使わずに、Scal9Grid ぽいことができました。

なんかVR空間のUIで使えそうな予感。いかがでしょうか。

別のアングルから見ると3D空間に浮いているのが分かります。

f:id:hiyokosabrey:20180430154332j:plain

 

テクスチャで頂点にマスクをすることで、動かしたい頂点を選び分けることができました。

 

今回は以上です。UMG推しではありますが、3D の UI制作についても記事を書いていけたらと思ってます。

 

ではでは

ステキな3Dウィンドウライフを!

 

 

 

 

 

 

 

 

 

 

 

 

UMGのテキストブロックで遊ぶ

とあるRPGの曲を作業用に聞きながらYoutubeの動画をチラ見してたら、テキストの表現方法がたくさんあったことに感動したのを思い出しました。で、ふと試してみようと思たったのが今回のネタです。過去記事で似たようなことをやってるのでその応用ってことになるのかな。

 

limesode.hatenablog.com

基本的に同じような作りです。ちょっと味付けが違う程度なので、細かい解説は省きます。

今回やろうとしている機能は2つ。

  • 1文字ずつタイプライター風に表示
  • 文字を震わせる

 

1文字ずつ出すだけだったら、テキストブロックひとつあればいいのですが、バラバラにする必要があって、さらに改行もするのでちょっと面倒なプロセスが入ります。

 

大雑把ですが、

  1. 改行付きの文字列(String型)を受け取る。
  2. 改行文字(エンジン内ではShift+Enter)で区切って文字列の配列を生成。
  3. その配列を行毎のHorizontalBoxに格納。
  4. 文字をぶるぶるさせる
  5. 一文字ずつAlphaを1.0にする

というフローでやってみます。

 

まず吹き出しテクスチャ。前回の記事に倣ってグレースケールで作りました。

f:id:hiyokosabrey:20180418231516p:plain

インポート設定で、フィルターを ニアレストにしておきます。

f:id:hiyokosabrey:20180418231828p:plain

拡大縮小の際のフィルタリングでドットをそのままにする設定です。

 

UMGのキャンバスに表示のON/OFFをラクするためにキャンバスパネルを置いて、中に

フキダシ画像と、文字を流し込むためのHorizontalBoxを並べます。

f:id:hiyokosabrey:20180418232541p:plain

 4行分に対応。

一応 HorizontalBoxは Size to Content のチェックを入れてあります。

f:id:hiyokosabrey:20180418232834p:plain

このHorizontalBoxを4つに分けたことで、文字列を「行」ごとに分割することになった

 最大の理由です。ローカライズを考えるならもうちょっと対策した方がいい気もしますが、あとから改行位置を調整するのを前提とした作りにしています。

Hiearchyはこんな感じ。

f:id:hiyokosabrey:20180419223029p:plain

 

Widgetブループリントを編集していきます。

HorizontalBoxはすでにキャンバスに置いてあるので、扱いやすくするために、Event Pre Constrct で配列化しておきます。

f:id:hiyokosabrey:20180419223215p:plain

 ブーリアン型の変数は、いきなりブルブルしないようにするためのフラグです。今はまだ false 。

 

まず関数を3つ。

 

ひとつ目

文字列を分解して、新しく1文字づつのテキストブロックを生成する関数。

f:id:hiyokosabrey:20180419224615p:plain

 

2つ目

指定した文字列(Delimiter)が文中に見つかると、それを配列にバラして格納します。

f:id:hiyokosabrey:20180419231005p:plain

 Parse Into Array はとても便利なノードです。

f:id:hiyokosabrey:20180419230145p:plain

 デリミタで使用した文字は消滅します。何が便利かって個別の値(この場合は文字列)を1文で扱うことができるという点です。本当は改行文字のようなOSやプラットフォーム依存の文字は避けるのが基本ですが、今回はお遊びということで。

 

3つ目

外部から文字列を受け取って表示する関数。上の2つの関数を組み込みます。

f:id:hiyokosabrey:20180419231325p:plain

 For Each Loop の処理が終わったら、表示開始になりますが、ひとまずイベントグラフに戻ります。

 

Event Tick でぶるぶるする処理を用意します。

Event Tick は、この WidgetViewportにAddされた瞬間から動き出します。

f:id:hiyokosabrey:20180419231611p:plain

 ランダムに ポジションを動かしますが、今回は微妙な値が連続しないようにInt型の乱数にfloat型の値を掛けています。

 

ここでフラグを見ています。文字の数が確定してないうちから処理するのは無駄なので、フラグが True になるまで処理しないようにブロックしています。

 

タイプライター風の動きをするのが、このカスタムイベント。

f:id:hiyokosabrey:20180419232511p:plain

ポイントなのがこの部分↓

f:id:hiyokosabrey:20180419232958p:plain

過去記事 『キーリピート機能をつくってみる』でも書いています。

 

だいたい用意ができたので、仕上げに3つ目の関数を編集します。

For Each Loop ノードの、Complete ピンの続きです。

f:id:hiyokosabrey:20180419233347p:plain

まず表示を Visible にして、フラグを True にしたら、タイマーノードです。

フキダシが表示されたら、人は目で追います。そのタイミングで文字を表示するのは視線誘導の効果が台無しなので、少し待ってあげるためのものです。Function Name のところに、タイピング処理用のカスタムイベントの名前をセットします。

 

これで、できあがりです。

 

 

確認

あとは適当にレベルブループリントから呼び出して確認します。

f:id:hiyokosabrey:20180419234030p:plain

 

こうなります。

f:id:hiyokosabrey:20180419234615g:plain

そう、とあるRPGというのは、UNDERTALE です。

その登場キャラの一人、フラウィのセリフです。

もう一つキャプリました。

f:id:hiyokosabrey:20180419235219g:plain

多分、まったく効果はない気がしますが一応ネタバレ対策で英語版にしてみました。

アイツの笑い声がよみがえります。

 

だいぶ遅れて遊んだのですが、ほんといいゲームですね。

読み物としてテキスト表現にこれほど凝った見せ方をしたゲームいままであっただろうか、というところも感動しました。UI表示を考えるとき、システム的に汎用性を意識するものですが、そんなのお構いなし、って感じです。まだ遊んだことのない方、ぜひ一度ご賞味ください。クレジット画面も凄まじい作りこみです。

 

今回も目コピーネタでしたが、楽しいのでまたやろうと思います。

ではでは

ステキなテキストブロック ライフを!

 

 

 

 

グレースケールテクスチャ 続き

Photoshopでいい感じのグレースケールテクスチャが作れたので、さっそくエンジンで検証します。もちろんUE4です。テクスチャだけの話だったらUnityでも使える内容ですが、ここからはアンリアルエンジンです。

テクスチャは2種類用意しました。

RGB24bpp の変換前のものと、 グレースケールに変換済みの2つです。どちらも同じ見た目ですが、ファイルサイズが違います。

f:id:hiyokosabrey:20180408134530p:plain

このテクスチャをインポートします。

 

どちらも同じ設定にします。このタイミングでGrayscaleを選択します。

f:id:hiyokosabrey:20180409215154p:plain

Compression SettingsGrayscaleに変えて、sRGB のチェックを外すと、晴れてリニアなグレースケールテクスチャとしてアセット化されます。

インポート後のDetailsタブを比べてみると・・・

f:id:hiyokosabrey:20180409215354p:plain

どちらも Resource Size8KbっておいおいPhotoshopでグレースケールにする意味なかったじゃん。なんか悔しいので、Contentフォルダの .uasset も一応チェック。

24bppの方は 3907Bytes 、 グレースケールの方は、 3745Bytes。うん、

ほんのちょっぴり差があった。ファイル名は2文字しか違わないので、何かしらおまけがくっついてるみたい。エンジンに取り込まれた後なら違いなんてなくて当たり前か。

 

さて次の検証。マテリアルの LinearGradientノードと勝負です。

f:id:hiyokosabrey:20180409220538p:plain

頑張って作ったテクスチャに何らかの変換がかかったりしてると悲しいので、計算で出力されるリニアなグラデーションと比べることで確認します。

「リニアな」というのは、0.0~1.0(0~255)までを何の補正もせず素直に使用している状態です。上の LinearGradientノードは値が偏らず均質なグラデーションになるうえ、テクスチャのような解像度というシガラミが無いのでゲージを作ったり背景などに大活躍です。

 

2つのテクスチャと、LinearGradientノードの合わせて3つで、マテリアルを作って、UMGで表示させてみました。

f:id:hiyokosabrey:20180409224435p:plain

なんだか明るいですが・・・3つとも同じように見えます。念のために適当な場所をサンプルとして差がないか確認します。

f:id:hiyokosabrey:20180409225839p:plain

残念ながら 0(黒)に近い部分で差異が出ています。画面キャプチャなので、エンジンの出力時に何らかの補正が入っているかもしれません。・・・というか全部にガンマ補正が入っているようです。中央が128じゃない時点で気づいてもおかしくないのですが、LinearGradientとの勝負でそこをスルーしてました。

sRGB空間な見た目なので、ノードで調整してみます。

f:id:hiyokosabrey:20180410232658p:plain

 

結果はずいぶんリニアっぽくなりました。

f:id:hiyokosabrey:20180410232726p:plain

ということで、何もせずそのままリニアなテクスチャを持ってきても、画面に表示されれば、sRGBになっているということが判明しました。

 

 今回リニアワークフローの検証をしたかったわけではないので、これ以上の深追いはやめておきます。そう、テクスチャの節約です。高解像度時代への橋頭保としてグレースケールテクスチャの扱い方を検証していたのでした。

 ちょっとサンプルを作ってみました。

用意したテクスチャはこれ。

f:id:hiyokosabrey:20180410235256p:plain

サイズは 1024x512pxです。圧がすごい・・・

次に用意したのは、

f:id:hiyokosabrey:20180410235408p:plain

サイズは 8x256px。

これをインポートして、マテリアルを作成します。

シンプルにマスクテクスチャとしての利用です。

f:id:hiyokosabrey:20180410235748p:plain

表示してみます。

ドーーーー~ン!という重低音が聞こえてきそうです。CMみたい。

f:id:hiyokosabrey:20180410235942p:plain

サイズ比較用に、解像度は同じ1024x512で RGBA8888 の 32bppのテクスチャを作ってみました。さっそく比較します。まずはG8から。

f:id:hiyokosabrey:20180411001212p:plain

f:id:hiyokosabrey:20180411001301p:plain

そしてRGBA32bpp

f:id:hiyokosabrey:20180411001313p:plain

f:id:hiyokosabrey:20180411001323p:plain

実に4倍の容量になります。圧縮すれば小さくなりますが、こういった文字やUI表示は劣化したテクスチャは悪目立ちします。凝った見た目は 32bppじゃないと無理ですが、クリアなエッジを保ちつつ、容量節約できた分バリエーションを持たせることができるグレースケール、どちらを採用するかはその都度相談しながら決めればいいかと思います。

 

大事なこと書くの忘れてました。UMGでは、直接グレースケールテクスチャを貼ることはできません。できなくはないですが見た目に赤くなります。しかも透過しない。

f:id:hiyokosabrey:20180411002631p:plain

これはチャンネルが 一つしかないためで、RGBAの4チャンネルのうち R

チャンネルのみに、グレースケールの値が適用されるからです。

 

普通にUMGで着色したい場合はこのようなマテリアルを用意します。

f:id:hiyokosabrey:20180411003527p:plain

これをImageパーツに適用すれば Color And Opacity で色が付けやすくなります。

f:id:hiyokosabrey:20180411003550p:plain

ちょっと手数が増えますが、テクスチャの容量が稼げるのが素晴らしいです。

マテリアルをちょこっと改造してインスタンス化できるようにしてみました。

f:id:hiyokosabrey:20180412000057p:plain

テクスチャサンプルパラメータノードに差し替えます。このノードに名前を付けて、テクスチャフォーマットをLinearGrayscaleに変えます。そして安全な状態にするために、

16x16程度の ■ ダミーテクスチャを作ってセットしておきます。

f:id:hiyokosabrey:20180412000539p:plain

このマテリアルからマテリアルインスタンスを作成します。マテリアルアイコンの上で右クリックして一番上にあるのを選択すると作ることができます。

f:id:hiyokosabrey:20180412000803p:plain

マテリアルインスタンスの中でテクスチャをセットする項目があるのでそこに用意したグレースケールテクスチャを登録します。

f:id:hiyokosabrey:20180412000901p:plain

あとはUMGで Image にセットするだけ。

 

基本はマスク的な使い方が一番向いてるのですが、ちょっと変わった使い方をしてみます。

 

Photoshopで雲模様フィルタを使うと簡単にシームレスなテクスチャが作れます。

f:id:hiyokosabrey:20180412053704p:plain

これを、Pannerでスクロールさせ、TexCoordに足してやると、

f:id:hiyokosabrey:20180412054420p:plain

 ゆらゆらと陽炎のように歪みます。水の中の表現としてもありです。

f:id:hiyokosabrey:20180412060452p:plain

 おなじ雲模様テクスチャに対してValueStepを使って掛けてみると、

f:id:hiyokosabrey:20180412055308p:plain

 ブループリントからScalaParameterノード ”Value” の値を 0.0~1.0 に変化させます。

f:id:hiyokosabrey:20180412060041p:plain

f:id:hiyokosabrey:20180412060050p:plain

f:id:hiyokosabrey:20180412060059p:plain

出現や消滅の演出に使えそうです。

 

といった感じで、まだまだ探せばネタはありそうですが、今回この辺にしておきます。

グレースケールテクスチャを使うと、テクスチャ容量を稼いでリッチな見た目を作るのができて楽しいです。

 

ではでは

豊かなグレースケールライフを!

 

グレースケールテクスチャ

ふと気になって、グレースケールについて調べることにしました。

UI表示のためのテクスチャは、アルファチャンネルを使った半透明で「抜き」を扱うことがほとんどなので、Photoshopで作ることが多いと思います。

 

で、ちょっと解像度の話

 最近のモニタ解像度は1080pがまだ強い印象ですが、PS4Proのせいで4K対応も考えなくてはなりません。解像度が低いうちは1文字が 8x8(実際は7x7) で下のような大きさでしたが、(っていつの話やねん!)

f:id:hiyokosabrey:20180408002322p:plain

↑この 320x240(4:3)をTV画面サイズとしたときに、単純に 1440x1080(4:3)に拡大して、だいたい同じようなバランスの大きさにしてみたら、1文字につき 約34pxは必要になります。

下図は、いったん1440x1080を横に拡張して 1920x1080(16:9)にしたものを上の画像に合わせて縮小したものです。

f:id:hiyokosabrey:20180408213303p:plain

 

拡大前と後を比較用に近づけて並べてみました。

f:id:hiyokosabrey:20180408004458p:plain

↑の画像のように拡大してボケボケだとかっこ悪いので、鮮明なテクスチャを用意したいものです。そのためにはテクスチャ解像度を上げることになるのですが、当然グラフィック用のメモリを圧迫します。UIのために容量を存分に分け与えてくれるなんてことは滅多に無いので、テクスチャの節約について考えなくてはなりません。解像度を確保するのに結構やりくりが必要です。

 そこで登場するのがグレースケールテクスチャ。単純なマテリアルだけで着色できるし、最近はシェーダーで加工するのが手軽になったので 結構活躍できます。何よりもファイルサイズが1/4で済むということは、RGBA32bitの絵のサイズと比べて4倍のサイズの大きさのテクスチャが作れるということです。

 

で、Photoshopの話

Photoshopでこのグレースケールテクスチャを作る方法は、大きく2つ。

  • 先にグレースケールで作業を開始する
  • 後からグレースケールに変換する

 実際に作業してみると問題が見えてきました。

気にしなければどうということはないですが、品質的に解像度の大きなモニタだと粗さが際立ちます。

先にグレースケールのドキュメントとして作業を始める場合の問題点は、ブラシカラーが K値(CMYKのK)で扱うので0~255階調ではなく、0~100の”%” というところ。

f:id:hiyokosabrey:20180408132636p:plain

小数点が使えないので、階調の少ない環境で作業することになります。あくまでもこれはブラシや塗りつぶしで細かく選択できないだけで、ぼかしフィルタやトーンカーブではしっかりと256階調が使われます。ゲージとかのリニアなテクスチャを作るにはちょっと工夫が必要です。あと個人的に気になるのは、作業効率という点でカラーが使えないので、UVのアタリ取りとして色分けできないところです。

 

後からグレースケールにした場合は要注意です。

Photoshopの初期設定だと、以下のようになります。

まず RGBで 256階調のリニアグレー

f:id:hiyokosabrey:20180408134530p:plain

これをグレースケールにモードチェンジするとこうなります。

f:id:hiyokosabrey:20180408134600p:plain

ピクセルを2倍に拡大していますが、ちょっと分かりにくいですね。

さらに部分拡大(1600%)にすると見えてきます。

f:id:hiyokosabrey:20180408134939p:plain

モニタによっては見えにくいですが、ディザ処理がされています。これはテクスチャの扱いによっては(雲とか煙みたいな繊細な半透明を扱うときとか)ノイズになります。

これを回避するには、カラー設定を変更します。

 

編集カラー設定

f:id:hiyokosabrey:20180408135432p:plain

変換オプションの「ディザの使用...」のチェックを外します。

チェックを外してからグレースケールにすると、ディザはなくなりましたが、

f:id:hiyokosabrey:20180408140037p:plain

キレイに並んでいたはずの段階がなんか怪しいことになります。

拡大してみるとなんだか不規則に並んでいます。よく調べてみるといくつもの段階が省略されているのが分かります。

f:id:hiyokosabrey:20180408140237p:plain

なぜこんなややこしいことをしているのか分かりませんが、Photoshopなりの愛か何かなんでしょう。いろいろ補正が入ってしまうのは仕方ないですが、なんだかやるせない感じに包まれつつカラー設定をいじっていたら、いい感じにできるやつを見つけました。

編集カラー設定

作業用スペースにある「グレー」を  sGray に変更します。

f:id:hiyokosabrey:20180408141818p:plain

この設定を変えてから、グレースケールにモードチェンジすると、損失のない素直なグレースケールに変換できました。

これなら、256階調のグレーでペイントできて、作業途中でカラーも扱えるのでいい感じです。

 

あとはこれを書き出せばテクスチャとしてエンジンで利用できます。

 テクスチャフォーマットはTarga形式。拡張子TGAで書き出します。このフォーマットは可逆圧縮で劣化しないし、結構いくつものビットフォーマットに対応してるので大変使い勝手がいいです。PhotoshopでTarga書き出しを行うと、普通だとポップアップが出て面倒です。

f:id:hiyokosabrey:20180408213911p:plain

しかもこのポップアップ直前の書き出し時の選択肢を覚えているので、切り替えが必要な時に一瞬戸惑うので嫌いです。アルファチャンネルの有無で見てくれればいいのに・・・

このポップアップがグレースケールで書き出す際は出ないので、ちょっとだけ幸せな気持ちになります。

 

書き出したファイルサイズを見てみるとちゃんと差があることが分かります。

 

 例えばこんな画像。サイズは 256x256px

f:id:hiyokosabrey:20180408214848p:plain

これを↓のようなチャンネル構成にしておいて

f:id:hiyokosabrey:20180408220155p:plain

それぞれのBPP(bits/pixel =1ピクセル当たりのビット数)で書き出してみました。

グレースケールを1とすると、だいたい3倍、4倍になってるのが分かります。

 

で、整理すると

グレースケールでのペイントや塗りつぶしは100段階の中からしか選べない。(256階調を使えないという意味ではない)

RGBモードのドキュメントで作業してからグレースケールに変換した際に、Photoshopの初期設定だと問題があったので、設定を変えないと、きちんとリニアなグレーにならない。

 

ということで今回はこの辺で。

 解決策が見つかったので、次回はエンジンに持っていって検証します。

ではでは

ステキなグレースケールライフを!

 

 

で、先日の話

ようやく勇気を出して、Twitterアカウントを作りました。

このブログにあるコメントしづらかったり、何かネタを提供してくださる場合などお気軽にご利用くださいませませ。お手柔らかに宜しくお願いします。

 

 

ボスゲージを作ってみる

RPGとかアクションゲームのボス戦なんかで、ボスキャラの体力がものすご~くたくさんあるのを表現したゲージがありますが、そのひとつ作ってみました。

f:id:hiyokosabrey:20180401224309j:plain

参考にしたのは、大人気モバイルゲームタイトルのFGOです。

普通は1本のゲージが何本もあるかのように見せるタイプが多いです。

例えば1本分がHP1500だとしてその4倍のHP6000をボスが持つ場合、単純に4本分削ることになります。その場合ゲージの色分けで表現すれば十分伝わると思うのですが、

f:id:hiyokosabrey:20180401231231p:plain

FGOは少し違いました。

長さは同じでも1本分にあたるHPの量が違うのです。それはゲージに添えられている数字が説明しています。また、ゲージの下にある◆アイコンがゲージのカラーと連動しています。この◆はいったい何を説明しているのか最初分かりませんでした。

単にゲージの本数を表しているだけでこんなアイコン置くかな・・・、と思いながら攻略サイトを眺めていると、どうやら、ボスキャラたちはゲージのカラー(段階)によって攻撃パターンを変えてくる仕様になっている様子。そういえばHP量を表す数字も、毎回カラーごとに一旦 0 になってから新しく仕切り直しています。ラスボスとかでよく見かけるやつです。HPがある程度減ったら形態が変わってHPが再充填されたりする。その段階を◆のアイコンで分かりやすくしてるようです。

いろいろ納得したところで、UE4で作ってみたのを紹介します。

 

色分けはマテリアルで

マテリアルでゲージを作るときは、テクスチャを使ったUVスクロールか、LinearGradientとValueStepコンビの2パターンを良く使います。今回は後者で。

f:id:hiyokosabrey:20180402003418p:plain

左の Valueと書かれた Scalar Parameter Valueノードの初期値は 1.0 にしておきます。

 

質感を出すためにテクスチャを追加します

f:id:hiyokosabrey:20180402003039p:plain 4x40 px のGrayScale

Addノードを使って間に割り込ませます。

f:id:hiyokosabrey:20180402003833p:plain

ブループリントからいじるためのパラメータ用のノードが3つあります。

長さを変化させるのが ScalarParameter です。

f:id:hiyokosabrey:20180402004237p:plain

この変数を 0.0 ~ 1.0 に変化させることになります。

f:id:hiyokosabrey:20180402005017p:plain

今回2本分のゲージをマテリアルで切り替えるようにした理由は、登場や退場演出などで、アルファフェードしたときに重なりを見せなくするためです。

マテリアルは完成。これをUMGに仕込んでいきます。

 

◆用のWdget

ゲージ下のアイコンを別Widgetで作ろうか悩んでみたけど、結局ラクするために用意することにします。

まずUMGのキャンバスに3つのImageパーツを重ねます。

f:id:hiyokosabrey:20180402215453p:plain

 

f:id:hiyokosabrey:20180402215933p:plain

真ん中のパーツには作っておいたマテリアルをセットします。このパーツにブループリントから色のパラメータを渡して着色します。

 

次に消滅アニメーションを用意します。

f:id:hiyokosabrey:20180402220450g:plain

ヒビが入って飛び散る動きをさせたかったのですが説明が長くなるので別に機会にします。ひとまず白くなって消えるだけですが、これはエフェクト用のパーツをアルファ値のフェードで登場させ最後のフレームで下敷きを残して消しています。

VANISHというアニメーション名にしておきます。

 

次にブループリントを編集します。

カラーを受け取る関数を用意します。

f:id:hiyokosabrey:20180402224457p:plain青いピン(引数:DetailsタブのInputsの項目で追加)はLinearColor型です。

f:id:hiyokosabrey:20180402224839p:plain

関数が用意できたら、EventGraphに戻って、カスタムイベントを一つ用意します。

これは消滅時のアニメーションを再生するためのものです。

f:id:hiyokosabrey:20180402225038p:plain

以上で◆アイコン用のWidgetは完成です。

 

 

HPゲージ本体

ゲージ本体のWidgetを作っていきます。

キャンバスはこんな感じ。

f:id:hiyokosabrey:20180402225837p:plain

ゲージ本体のパーツは、マテリアルをセットしておきます。

f:id:hiyokosabrey:20180402230251p:plain

マテリアルでゲージを変化させるので、このゲージの長さは適当でOK。

 

左下の Horizontal Box は Panelカテゴリのパーツで、ブループリントから子供Widgetを追加すると自動で水平方向に並べてくれる便利なやつです。サイズが小さいのは中身に合わせて可変する設定 Size to Content が 有効(True) になっているからです。この時点では中身はカラです。

f:id:hiyokosabrey:20180402230657p:plain

下敷き以外のパーツは、 必ず Is Variable にチェックを付けておきます。

f:id:hiyokosabrey:20180402231201p:plain

これでブループリントからいじることができます。

UMGは以上です。

 

ではブループリントを編集していきます。

まずは Event Pre Construction イベントから。

f:id:hiyokosabrey:20180402231424p:plain

このイベントはコンパイルした時点で処理される特殊なイベントです。

変数の初期値をセットしたりするのに向いています。

 HPの段階は配列変数で管理したいので、段階ごとのカラーをLinearColor型の配列変数で用意します。マテリアルを頻繁にいじることになるので、ここで Dynamic Mterial Instance 作って変数化しておきます。Get Dynamic MaterialノードのReturn Value ピンの上で右クリックして Promote to Variable を選択するとラクちんです。

 普段 マテリアルは Static(静的)なものとして扱われます。ブループリントからいじりたい場合はDynamic(動的)なものとして扱います。この辺はお約束として覚えておけばいいと思います。

 

つぎに関数を5つほど用意します。

 

まず一つ目 簡単なとこから。

showVital

f:id:hiyokosabrey:20180402232623p:plain

引数でもらったInt型の値を、UMGのテキストブロックに流し込みます。

 

2つ目

setVitalColors

f:id:hiyokosabrey:20180402232809p:plain

 ゲージのマテリアルにカラーを渡す関数です。

 

ここで、段階ごとのHPを配列で受け取るための変数を用意します。

f:id:hiyokosabrey:20180402233130p:plain

用意できたら3つ目の関数

setVitalValue

f:id:hiyokosabrey:20180402233348p:plain

今現在のHPを、その段階に設定されているHP(配列に格納)で割ると、比率が出ます。それをマテリアルに渡すとゲージが変化します。今回ゲージを右から左に向かって減らしたいので、1.0から引き算しています。

 

ここで、Int型の変数を2つ新しく追加します。名前は Vital と Level にしました。

ボスのHPを保持するのと、段階を保持する変数です。配列にはしません。

 

この時点で 変数リストはこのようになってます。

f:id:hiyokosabrey:20180402234335p:plain

上の方のUMGパーツたちは、Is Variable にチェックをつけるとここに並びます。

一番下の Boss~ はこの後説明します。

 

4つ目

initGauge

f:id:hiyokosabrey:20180402233803p:plain

先に用意した関数を並べます。引数で指定した段階のHPでグラフをセットします。

開始時と段階が進んだ時にこの関数が呼ばれます。

 

5つ目の関数をに行く前にマクロを作ります。

ブログで説明するには長くなるので、マクロにまとめました。

initSubVitalIcon

f:id:hiyokosabrey:20180402235623p:plain

 受け取った配列の数から1ひいた分だけ ◆用Widgetを生成して並べます。後でいじるので、生まれたばかりのWidgetを配列の形で格納(空っぽの配列にAdd)しています。Create Widget ノード の Return Value ピンの上で右クリックして Promote to Variable を選択した後、いったんそのSetノードをグラフから削除します。そしてDetailsタブの方で配列化します。

f:id:hiyokosabrey:20180403000208p:plain

 

いよいよ5つめの関数

setupBossVital

f:id:hiyokosabrey:20180403000636p:plain

この関数が外のブループリントから、ボスのHPを配列で値をもらいます。

 

最後にカスタムイベントを作ります。

このイベントでダメージ分を受け取ってゲージを減らします。

updateVitalValue

f:id:hiyokosabrey:20180403001330p:plain

ダメージの値を受け取って、現在のVitalから引き算します。それを再び変数にセットして、判定を取ります。0以下、ということはマイナスになったかどうかを確認します。

 

いいえ(0以下ではない)だった場合

f:id:hiyokosabrey:20180403001831p:plain

そのままゲージの見た目を更新

 

はい(0以下)だった場合

f:id:hiyokosabrey:20180403002037p:plain

 段階を一つ進めます。こここでも段階がまだあるかどうか判定してから次に進みます。

下段はもう段階がないので、事実上ボスは倒したことになります。

 

以上で完成です。

 

さっそくレベルブループリントからテストしてみましょう。

f:id:hiyokosabrey:20180403002655p:plain

とりあえず段階は4にしてみます。

この状態では、ゲージが減らないので、シミュレーション用のInputイベントを使います。

UE4はキー入力のイベントを扱うノードが充実してるので好きです。

f:id:hiyokosabrey:20180403003013p:plain

 スペースキーを押すたびに、500~5000のランダムな値をゲージWidgetの関数に送り込んでいます。ダメージとして計算してくれるはずです。

 

f:id:hiyokosabrey:20180403004335j:plain

f:id:hiyokosabrey:20180403004347j:plain

無事動いています。

f:id:hiyokosabrey:20180403004414j:plain

ちゃんと下の◆も連動しています。

f:id:hiyokosabrey:20180403004446j:plain

カラーを配列にしているのですが、0番目を透明にしている訳は↑これです。

f:id:hiyokosabrey:20180403004930p:plain

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

 

今回はFGOの敵HPゲージを目コピしてみましたが、なかなか楽しかったので、また気が向いたら既存のタイトルを再現してみます。

 

ではでは今回はこの辺で

ステキなボスゲージライフを!