みつまめ杏仁

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

3DメッシュでつくるUI ー カーブ利用編

 日が落ちるのが早くなってきましたね。帰宅中に夜道を歩いていると、ふいに稲の枯れた匂いが漂ってきたので、見ると田んぼの稲がすっかり刈られていました。昼間はまだ暑いので意識していなかったんですが、なんだか急に夏の終わりを感じて寂しく思うと同時に、美味しい食べ物がいろいろ出てくる季節なのでワクワクもしています。

 さてさて、この頃はゲームエンジンが身近になって、3Dを利用するためのハードルがものすごく下がった、もはや無いのではないかとさえ思います。2Dアセットを扱うことが圧倒的に多いUIデザイナーとしては、周りのモデラーさんと比べてしまったり、手を付けるとしても今一つ成果物のイメージがUIと結びつきにくいとか、習得するのも時間がかかりそうだとか、サブスクやライセンス料が高いDCCツールだと家でコッソリというのも難しかったり、いろいろと心理的ハードルが高く、キビシさを感じておられる方も多いのではと思います。

 そこでぼくは、あくまでも 2DUI の延長線上で、部分的に3Dに置き換えていくという作り方を提案したいなと思った次第。

 イラレや手書きじゃなくて、リアル質感のあるUIを作りたいから3Dを勉強したい、というのは残念ながらぼくでは力不足なので、技術書か他のサイトをあたってもらうしかないですね。ゲーム画面の中で、リアルタイムレンダリングで、無理なく表現できる少しリッチなUI表現を実装するために というコンセプトで書いていきます。

 

 

今回サンプルとして用意したのはモーダルウィンドウです。

画面に対してかなり大きな面積を占めるうえに、常駐させることが多く、何度も目にするのであまりテクスチャの解像度を低くすることもできないので、メッシュで作るのにちょうどいいからです。

f:id:hiyokosabrey:20211011233210j:plain

 このウィンドウベース(下敷き)を3Dメッシュで作ることで、テクスチャの解像度を稼ぎつつ、効率のよいテクスチャアトラスを作ろうぜ、というのが目的です。
中央の単色ベタの部分を有効利用したいなと。

 

 スプライトやImageで複数のパーツに分割するとテクスチャの容量を節約できるけど、いくつかのパーツに分けてくっつけて表示するというのも、ちょっと組み合わせるのが手間なうえに、圧縮によるピクセルの荒れを回避する必要があったり、アニメーション時に隙間やズレが出たり、フェード時に重なりが見えてしまったり、というのを心配してしまうのだけれど、最近あまりそういった悩みを聞かなくなった。容量の心配しなくていいほど余裕があるのか、9スケールグリッドみたいなデザインを選択して回避しているのかもしれない。

f:id:hiyokosabrey:20211013231519p:plain

 デザインでグリッドに縛られすぎるのも、ゲームの雰囲気によってはお行儀が良すぎて絵的に面白くないし、容量の負担を大きくせずに大胆な形状を採用できるのはメッシュが向いていると思うのです。

 

 スプライト等の2Dでは矩形でしか描画できないのに比べて、ポリゴンのあるとこしか描画しないので、不要なピクセルの半透明ブレンドの計算を減らすことができます。また9スケールグリッドのような部分的にテクスチャを伸ばすことも楽勝なので、柔軟なデザインに対応できます。どんなに複雑な形状でもOneオブジェクトとして扱える。

 テクスチャの容量が節約できると、テクスチャのロード時間が減るし、常駐量が少なくなれば、メモリ管理に余裕ができるし、もっと他にリッチな表現が欲しいときの貯金としてやり繰りできます。

 

 さすがにメリットばかりじゃなくて、レイアウトがカメラ基準だったり、色味の調整に悩んだり、メッシュ内のポリゴン順で悩んだり、扱うツールが増えたりするので「なにがなんでもは3Dメッシュじゃい!」とは言わないですが、3Dメッシュによって表現の幅やできることが広がるのは自信を持って言うことができます。タイトル名は書けないのですが自分のかかわったタイトルでは結構な頻度で3DでUI作ってます。

 3DでUI作ってるというと、ほぼ例外なく立体的な見た目を想像されるのですが、ぼくは テクスチャ容量節約描画負荷削減 のために使うことが多いです。なので、3Dであることを気づかれないのは寂しくもあるけど、ある意味自慢です。最近は頂点アニメーションもやりやすくなったので楽しいですね。そのうちUVアニメーションの楽しさとかも記事にしていきたいと思ってます。

 

 

 というわけで、今回作ったテクスチャはスカスカですが、下図の斜線部分も余すことなく使っていきたいのです。

f:id:hiyokosabrey:20211013234945p:plain

 

 

 

f:id:hiyokosabrey:20211016010033p:plain

メッシュの作成は Blender を使用します。ver 2.92 を使って記事を書いていますが、ver2.93でも問題なく進められます。

今回作るものに必要な操作は書いていますが、インストール方法や基本操作については省かせていただきます。

 

 

まず、カーブを使ってみるところから。

カーブを使わなくても問題ないのですが、いろいろ便利に使える手法なので、記事にしておきます。

 

 

ObjectModeで Add > Curve > お好きなカーブタイプ

f:id:hiyokosabrey:20211007233309p:plain

カーブを選ぶとビューポートにオブジェクトが配置されます。

カーブは、厚みなどのボリュームがないので、作成時のカメラの角度によっては追加されたことが分かりにくいことがあります。
テンキーの [ 1 ]、[ 3 ]、[ 7 ]、を押して探します。

f:id:hiyokosabrey:20211007234654p:plain

f:id:hiyokosabrey:20211007234702p:plain

f:id:hiyokosabrey:20211007234709p:plain

これでも見えない場合はカメラが離れすぎているかもしれないのでピリオド [ . ] キーを押してみると見つかることもあります。サイズが大きくないので、スケールで大きくするのもありです。

 

パースペクティブビュー(奥行きのある視点)で作業すると歪みが出やすいので、

平行投影にします。切り替えは テンキーの [ 5 ]

f:id:hiyokosabrey:20211007235929g:plain

 

向きは後から回せるので、とりあえずXY面で作業していくことにします。

 

[ Tab ]キーを押して、ObjectMode から EditModeに切り替えます。

f:id:hiyokosabrey:20211008002303p:plain

カーブの両端に方向線が出てきます。(ベジェ曲線を選択した場合)

 

 

カーブを伸ばす

カーブを伸ばしたいどちらか一方のアンカーポイントを選んで [ E ] キーを押す。

f:id:hiyokosabrey:20211009091758p:plain

 

そしてすぐにドラッグすると新たなアンカーポイントが増えます。

f:id:hiyokosabrey:20211008002618p:plain

 

カーブを閉じる

閉じるには両端のアンカーポイントを選択して、[ Alt ] キー押しながら [ C ]キー

f:id:hiyokosabrey:20211009004530p:plain

 

無事閉じたら、形を整えていきます。

アンカーポイントと方向線の端の点が選択できるので、[ G ]キーを押していい感じの位置に移動させていきます。

f:id:hiyokosabrey:20211008004341p:plain

アンカーポイントや方向線を選んだ状態で、[ R ]キーを押すと、方向線を回転、[ S ]キーで長さを調整してカーブの流れを整えていきます。

 

マウスで対象を直接ドラッグする方法に慣れてると、結構戸惑うと思います。

Blenderの場合、

  1. 対象を選ぶ
  2. アクション(何をするか)を決める
  3. 操作する(アクションによっては追加で設定や調整までできるものがある)

という3段構えで触ることが多いです。

対象の種類や状態によってできることとできないことの差が大きくて、状況依存としてコンテキストから選ぶほうがユーザーにとっては選びやすかろうという配慮だと思います。

 

 

アンカーポイントの追加

アンカーポイントを後から増やすには、セグメントの分割という操作になります。

2点を選んで

f:id:hiyokosabrey:20211010111611p:plain

ヘッダーメニューから Segments > Subdivide

f:id:hiyokosabrey:20211010111740p:plain

f:id:hiyokosabrey:20211010111906p:plain

 

 

アンカーポイントの削除

削除したいアンカーポイントを選択した状態で

f:id:hiyokosabrey:20211010114454p:plain

 [ X ]キーを押すとポップアップが出ます

f:id:hiyokosabrey:20211010114129p:plain

Vertices を選ぶと消えます。

f:id:hiyokosabrey:20211010114328p:plain

 

アンカーポイントを2点選んでこの操作を行うと、間のセグメントを削除できます。

f:id:hiyokosabrey:20211010115044p:plain

f:id:hiyokosabrey:20211010115053p:plain

ショートカットキーを使いましたが、ヘッダーメニューからも同じ操作が可能です。


 

 

大体カーブの扱い方がわかってきたところで、

画面デザインからテクスチャを作って、Blenderに持ってきます。

 

まずテクスチャはこんな具合に入れました。

f:id:hiyokosabrey:20211011235142p:plain

1920x1080の画面サイズを想定しているので、テクスチャのサイズは 2048x1024 と巨大です。画面デザインからダイレクトに移植しました。

作業しやすいように、背景は真っ黒です。
PSDで書き出したらBlenderのウィンドウに直接ドロップします。

f:id:hiyokosabrey:20211011234456p:plain

f:id:hiyokosabrey:20211012230240p:plain

ObjectModeじゃないとドロップできないので注意

あと、作業するビューにドロップしないと、カメラの向きを変えると回転してしまいます。

f:id:hiyokosabrey:20211011235958p:plain

色が濃すぎるので、半透明にします。

ドロップした画像オブジェクトを選択した状態で設定パネルから調整できます。

f:id:hiyokosabrey:20211011235739p:plain

f:id:hiyokosabrey:20211012000009p:plain

実はこれ、テクスチャではなく、下絵として使います。

 

ここにカーブを追加したら、この絵を下敷きにして形を整えていきます。

f:id:hiyokosabrey:20211012001110p:plain

少し外側を通る感じ。

f:id:hiyokosabrey:20211012001329p:plain



 



 

この「カーブ」は「メッシュ」にしないとゲーム画面で描画できません。

アウトラインフォントがすでに実装できているので、いずれはそのままアセットとしてレンダリングできる時代が来るとは思いますが、いましばらくはメッシュと仲良くするしかないようです。

 

さて、モードを ObjectMode に切り替えます。

f:id:hiyokosabrey:20211012000950p:plain

 

カーブからメッシュに変換する方法は2つ

一つは ヘッダーメニューから Object > Convert to > Mesh

f:id:hiyokosabrey:20211009000703p:plain

 

もう一つは、カーブの上で右クリック > Convert to Mesh

f:id:hiyokosabrey:20211009001326p:plain

 

この操作をした直後に、オプション設定のポップアップが画面左下に出るので、

その中にある Keep Original を有効にすると、カーブをバックアップできます。

f:id:hiyokosabrey:20211009003004p:plain

f:id:hiyokosabrey:20211009003320p:plain

 

コンバートしても見た目に変化しないので、EditModeに切り替えます。

f:id:hiyokosabrey:20211012002447p:plain

 ↓頂点をすべて選んだ状態。

f:id:hiyokosabrey:20211012002302p:plain

頂点の数が結構多い印象だけど、後で減らすのでひとまずこれで進めます。

画像がちょっと分かりにくいので下敷きはいったん非表示で説明していきます。

f:id:hiyokosabrey:20211012010406p:plain

 

まだ、頂点とエッジ(頂点同士を結ぶ線)しかないので、面を張ります。

 

頂点すべてを選択した状態でヘッダーメニュー Face > Fill

f:id:hiyokosabrey:20211009004219p:plain

Fill のショートカットは [ Alt ] + [ F ]

f:id:hiyokosabrey:20211012004831p:plain

たくさんの三角形ポリゴンで面を構成されています。

おそらく計算やデータの順番やらいろいろな処理の効率が最大になるよう考慮して三角形分割されてると思うので、人間が手で分割するよりは無駄がない、はず。

 

ここまでくると頂点を減らすモディファイアが使えるようになります。

f:id:hiyokosabrey:20211009102746p:plain

モディファイアは、例えるならPhotoshopのレイヤー効果みたいな位置付けのものです。元のオブジェクトを非破壊なまま、さまざまな形状、状態に変化させてくれるという大変ありがたい存在。パラメータ調整で最終結果をいつでも確認できるので重宝します。

今回使うモディファイアは、Decimate

f:id:hiyokosabrey:20211009094707p:plain

 

f:id:hiyokosabrey:20211009102219p:plain

ObjectModeで確認しながら減らすことができます。

上図の設定パネルから Ratioを調整します。Ratioのところにある棒グラフの先端付近をマウスで左右にドラッグするとリアルタイムに頂点数が変化します。

f:id:hiyokosabrey:20211012005211p:plain

Convert to Mesh したときの 96頂点 から 34頂点 に減らしてみました。

下絵を表示してみます。

f:id:hiyokosabrey:20211012005331p:plain

大丈夫そうです。ここでハミ出していてもあとから簡単に調整できます。

 

さて、このポリゴンに対して、縁取りをつくります。

次に進む前に、モディファイアを適用する必要があります。

f:id:hiyokosabrey:20211009104231p:plain

これで形状をFIXできます。

 

ちなみに上図の の右にある × ボタンをクリックすると、モディファイアを破棄して、なかったことにできます。「レイヤースタイルの破棄」みたいなものです。

f:id:hiyokosabrey:20211009105116p:plain

これで後戻りはUndoのみ。

 

EditModeで頂点すべてを選択した状態でヘッダーメニュー Face > Inset Faces

f:id:hiyokosabrey:20211009004219p:plain

Inset Faces を選択したら、クリックしないようにマウスを移動(ドラッグしない)させて幅を検討します。

f:id:hiyokosabrey:20211009105748g:plain

このとき、なんだか幅が均等じゃないな思ったら、カーブが歪んでいた可能性があります。

f:id:hiyokosabrey:20211009144156p:plain

真横から見てまっすぐになっていない場合に、縁取りが不均一になります。

ObjectModeで、スケールを 0 (上図の場合青い軸線方向につぶすので Z軸を 0)にしてつぶしてからヘッダーメニュー Object > Apply > Scale

 

これでOK、となったらクリックしてFIX。

適当にクリックしても、直後であれば詳細設定のポップアップが出ているので、そこで微調整できます。

f:id:hiyokosabrey:20211009125738p:plain

Thicknessが縁取りの太さです。フォームの上でマウスでドラッグが便利。

Select Outer にチェックをつけるとハイライトされているポリゴンが反転します。

f:id:hiyokosabrey:20211009130432p:plain

ポップアップ以外をクリックすると完全にFIXします。それまでは自由に調整できます。

f:id:hiyokosabrey:20211012010103p:plain



 

縁取りのポリゴンを選択した状態で『UV展開』します。

こういった 『ぺらい』メッシュだと、UV展開という言葉がしっくりこないのですが、各頂点ごとの、テクスチャUV座標を決める操作のことを指して言う言葉だと、覚えておくといいですよ。

 

トップメニューにある UV Editing ボタンをクリックして、ビューポートのレイアウトをUV編集レイアウトに切り替えます。

f:id:hiyokosabrey:20211009132243p:plain

右側のビューポートが、デフォルトな感じに戻された場合は、テンキー[ 7 ] を押して、[ 5 ]キーで平行投影にしたり、ワイヤーフレーム表示にしたりして、見た目を整えます。

 

ポリゴンの選択が外れてしまったときは、

f:id:hiyokosabrey:20211009134001p:plain

編集対象をポリゴンにして、

f:id:hiyokosabrey:20211009134308p:plain

ひとつだけ選択します

f:id:hiyokosabrey:20211009134350p:plain

ヘッダーメニューの Select > Select All by Trait > Faces by Sides

f:id:hiyokosabrey:20211009142714p:plain

f:id:hiyokosabrey:20211009143153p:plain

全部のポリゴンを選択していても特に問題はないのですが、この操作を覚えておくと後でラクができます。

 

ヘッダーメニューから UV Unwrap

f:id:hiyokosabrey:20211009141644p:plain

UVエディタが下のようになります。

f:id:hiyokosabrey:20211009145629p:plain

まだ、何もテクスチャを読み込んでいないので、デフォルトの正方形のイメージが表示されています。

90度回った状態になるのですが一旦置いておいて、テクスチャを読み込みます。

テクスチャを読み込んでから、Unwrap する方が手間が減っていいのですが、UV座標の特性を説明したくてこのような流れにしています。

 

UVエディターのヘッダーメニューにある +New ボタンの左側にあるプルダウンからテクスチャ画像を選択。下絵としてドロップした画像がリストアップされているはずです。

f:id:hiyokosabrey:20211012232037p:plain

プルダウンリストの中に見つけられなければ、Open ボタンから探して読み込みます。

 

f:id:hiyokosabrey:20211012232608p:plain

アスペクト比が変わったので変形してしまいました。

これがUV座標空間の特徴です。

最初に Unwrap した際に展開したUV座標から何も変わっていないのです。

UV座標は、座標と言いつつもテクスチャの形状に関係なく、端から端までを0~1.0 で扱います。

f:id:hiyokosabrey:20211012234001p:plain

※環境によっては、左下が 0原点で扱われることがあります

 

このため、テクスチャのアスペクト比が変わると、変形してしまうのです。

メッシュの形には影響しませんが、テクスチャ作成がちょっと面倒なことになります。

 

余談ですが

この特性を利用すると、プラットフォーム等による解像度の変更作業がとても簡単になります。

例えば 2Kで作ってきたところで、あとから4K対応することになった場合。

テクスチャの解像度を変えるだけで対応完了です。スプライトのようにピクセル座標で管理していると、大変な手間になります。

※エディタ上ではピクセル座標は整数で扱いつつも、内部のデータではUV座標という開発環境もあると思われるので確認は必須

いくらUV座標が効率的とはいえ、小数を扱うので、苦手な人は辛いかもしれません。

 

 

さて、変形した比率を正常なアスペクト比にします。

UVエディターで作業します。

ここで頂点をすべて選択して [ S ]キーを押すか、

Scaleボタンをクリックするとスケール調整モードになります。

f:id:hiyokosabrey:20211013000913p:plain

[ S ]キーを押した場合はマウスを動かすだけでとサイズが変更できます。操作パネルからスケール調整モードにした場合は、マニュピレーターをドラッグします。

ここはアナログな調整ではなく、数値でサクッとリサイズします。

スケールを少し触ってクリック(マニュピレータの場合はマウスボタンから指を離す)すると、UVエディタのビューポート左下に Resize のポップアップが出るので、そこで数値を入力します。

f:id:hiyokosabrey:20211010000357p:plain

Scale X を 0.5 にして YとZ は 1.0 にします

f:id:hiyokosabrey:20211009234931p:plain

f:id:hiyokosabrey:20211013000607p:plain

 

 

つぎに [ R ] キーを押すか、Rotateボタンを押して回転モードにします。

f:id:hiyokosabrey:20211013001317p:plain

これもスケール同様にして操作すると Rotate のポップアップが出ます。

-90 と入力すると元の向きになります。

f:id:hiyokosabrey:20211010000916p:plain

f:id:hiyokosabrey:20211013001948p:plain

 

あとは、テクスチャのデザインに合うようにサイズと位置を調整します。

[ S ]キーで スケール

[ G ]キーで移動

[ホイール] ズームイン/アウト

[中ボタン]ドラッグでスクロール

  ※Blenderのデフォルト操作設定

 

f:id:hiyokosabrey:20211013003317p:plain

 

完成まであと少し。

 

 

 

 

縁取りを除いた中身をほったらかしにしてるので、残りの頂点をUV展開します。

3Dビューポート側のヘッダーメニューから Select > Invert

f:id:hiyokosabrey:20211009142714p:plain

で選択箇所が反転します。

f:id:hiyokosabrey:20211010003102p:plain

再び  UV > Unwrap

f:id:hiyokosabrey:20211009152925p:plain

f:id:hiyokosabrey:20211014001620p:plain



この頂点をマウスドラッグで矩形選択して、[ S ]キーで適当に小さくします。

f:id:hiyokosabrey:20211014001836p:plain

 

これも Resize のポップアップから、Scale X と Y に数値を入力。

f:id:hiyokosabrey:20211010003737p:plain

スケールを ゼロ にすると 1点に集約されます。

f:id:hiyokosabrey:20211014002123p:plain

これを、邪魔にならない場所に移動します。[ G ]キー

f:id:hiyokosabrey:20211014002135p:plain

メッシュはこれで完成です。

 

FBXとかで書き出してエンジンに持っていくことができます。

 

UVが思った通りにあたっているか、確認しておきます。

まずシェーディングタイプをマテリアルにします。

f:id:hiyokosabrey:20211014003103p:plain

f:id:hiyokosabrey:20211014012602p:plain

マテリアルがアサインされていないので、生ポリゴンの状態です。

 

新しいマテリアルをアサインします。

f:id:hiyokosabrey:20211014012450p:plain

Base Color のところにある 黄色の丸をクリック ③

f:id:hiyokosabrey:20211014013657p:plain

ポップアップウィンドウが出てくるので、Image_Texture を選択 ④

f:id:hiyokosabrey:20211014013946p:plain

表示内容が変化するので、UVエディターのときと同様に、プルダウンからテクスチャ画像を選択します ⑤

f:id:hiyokosabrey:20211014014231p:plain

 

f:id:hiyokosabrey:20211014014657p:plain

デフォルトのマテリアルとシェーダーで描いているので色味がおかしいですが、ここではUVが正しく展開できているかが大事なので、歪みが出たりしていなければOK。

 

メッシュはこれで問題なくエクスポート(書き出し)できます。

エクスポート方法については、開発環境に依存するので、今回説明は省かせていただきます。

 UE4とUnityは、FBXをサポートしているので、ぼくはFBX形式で書き出します。

 

残るはテクスチャ。

テクスチャに、メッシュで使用するUVの範囲をわかるようにしておくと、ギリギリまでスペースを使うことができます。

うっかりUV展開している範囲に他の余計なピクセルが侵入しないようにしたいので、UVレイアウトを画像で書き出す機能を利用します。

 

UVエディタ上で、UVの頂点を選択した状態で、

f:id:hiyokosabrey:20211015001333p:plain

UVエディタのヘッダーメニューから UV > Export UV Layout

f:id:hiyokosabrey:20211009153038p:plain

ファイル書き出しのダイアログが出るので、指定した場所にそのままPNGフォーマットで書き出します。

f:id:hiyokosabrey:20211009154612p:plain

 


この書き出した画像をPhotoshopで開きます。

f:id:hiyokosabrey:20211015001802p:plain

半透明なのと黒色で分かりにくいですが、このレイヤーをテクスチャ用のドキュメントに移植します。

Photoshopでドキュメント間でレイヤーを移すとき、

[ Ctrl ]+[ Alt ]+[ Shift ]を押しながらドロップすると、まったく同じ位置に配置できます。

f:id:hiyokosabrey:20211015003158p:plain

           ※UVレイアウトの画像が見えにくいのでカラーを反転しています

 

f:id:hiyokosabrey:20211015004752p:plain

ぴったり。同じサイズのドキュメント間で有効な隠し技です。

 

このUVレイアウトを避けてさえいればぎりぎりまで使えます。

書き出す際は、レイヤーを非表示にします。

 

仕上げに圧縮対策をします。

アルファチャンネルで透明になるピクセル付近のカラーを広げて塗りつぶしておく感じで。

↓今はまだ周りに何もないので手を抜いて矩形で塗ってる状態。

f:id:hiyokosabrey:20211015005438p:plain

RGBチャンネルは ↑

アルファチャンネルは ↓

f:id:hiyokosabrey:20211015005807p:plain

これでテクスチャも用意できました。

 

 あとは、エンジンでマテリアルとかシェーダーを用意してくっつければ画面に表示できると思います。

 

f:id:hiyokosabrey:20211015021950j:plain

f:id:hiyokosabrey:20211015231904j:plain

 

 エンジンの環境によっては、描画のタイミングや思ったような色にするのに設定が必要な場合もありますが、結構手軽に表示させることができます。慣れてくると5分もかからないです。マテリアルやシェーダーについては、一度汎用的なのを用意すれば、特殊なことをしない限り使いまわせます。

 インポートやエクスポートの方法については、エンジンや開発環境に依るところが大きいので書くのをやめました。DCCツールに書き出すためにスクリプトを用意する開発現場もあるかと思います。余計なデータをくっつけて書き出さない、余計なデータを取り込まない、というのに気を付けて、パラメータやスイッチ等のパラメータを試行しながら最適な手順を見つけることになると思いますが、UIの場合アニメーション関連(スケルトンとかボーンとか)は不要でいいと思う。マテリアル関連も、エンジンで組むのでそれほど必要になったことはないかな。

 

 ちょっとしたUIパーツを、わざわざ3Dメッシュで作るのは、手間が増えるだけなので、オススメはしませんが、見た目に驚きを与えたり、データ効率が良くなるのであれば、技術習得も兼ねて積極的に使っていきたいですね。

 

今回は以上になります。

次回は、カーブを使わずに四角形を分割しながら作る方法か、カーブで作ったゲージのどちらかを書いてみようかと考えています。

 

ではでは

素敵なメッシュUIライフを!

HPゲージをいろいろいじってみよう ー もっと動きをつける

前回の記事でいろいろ見た目をアップさせる小技を紹介しましたが、今回はいろいろ動きのあるものを入れたものを紹介していきます。

あくまでも一例にしかならないのですが、いくらかヒントになれば幸いです。

 

先の記事からの続きとなっていて、値を変える関数や表示のテストについては解説は省いていますので、いきなりこの記事からだとわかりにくい箇所があると思いますので、過去記事のリンクを貼っておきます。

limesode.hatenablog.com 

HPゲージをいろいろいじってみよう ー 成長するゲージ - みつまめ杏仁

HPゲージをいろいろいじってみよう ー 見た目を工夫する - みつまめ杏仁

 

 

INDEX

 

 

ダメージを受けると揺れるやつ

f:id:hiyokosabrey:20210828121816g:plain

揺らすためのカスタムイベントを用意します。

UMGのタイムラインでアニメーションを作成した場合、以下ようになります。

f:id:hiyokosabrey:20210828114934p:plain

他のアニメーションと被る場面があると、気軽にタイムラインアニメーションを使えないということもあるかもしれません。ということでノードでランダムな動きを作ってみます。

 

ひとくちにランダムな揺れというと、ランダム揺らし警察に職質されそうなのでビビリながら書くのですが、実際いろんなアルゴリズムや手法があって、結局のところこだわりポイントの差がすべてのような気はしています。

ということで今回は円を使ったランダム座標です。

矩形の範囲内の座標をランダムにチョイスする方法だと、シンプルですが、原点からあまり動かない可能性があります。ある程度原点から離れた位置にぶっ飛んでほしいという気持ちがあったので強制的に中心から離そうと考えて円の動きに決めました。f:id:hiyokosabrey:20210828114021p:plain

サインとコサインに渡しているのは ラジアンです。ラジアンは円1周で 2π なので -3.14~3.14 でランダム値をゲットしています。0~6.28 とかでも同じになります。

角度(Degree)に変えることもできます。

サイン、コサインノードに掛け算しているのは半径に相当します。サイン、コサインは基本的に -1 ~ 1 の値を返すので、そのままだと小さすぎるのを大きくして使っています。ここを加減することで、揺れ幅が調整できます。

 

UMGで位置を変えるのは2種類の方法があります、元の位置に戻すことを想定すると Canvas Slot の Position を変えるのではなく、 Render Transform の Translation を使うのがベスト。

これについては画像付きで解説している過去記事を貼っておきます limesode.hatenablog.com

 上に伸びてる赤いラインは、いつものアイツ、 Set Timer by Eventノードです。

f:id:hiyokosabrey:20210828124110p:plain
一定回数揺らすと終了するようにしたいので、回数をカウントする Int型の変数を用意して利用します。

 

 

このカスタムイベントをゲージの長さを変更する際に呼び出される関数に追加します。

f:id:hiyokosabrey:20210828124520p:plain

減らすときだけ揺らしたいので、このイベント呼ぶ側にその選択をさせるため、カスタムイベントにBoolean(ブーリアン型)のピンを追加。

 

テストの際にレベルBPからこのイベントを呼び出しているので、カーソルキーの左を押したときだけ True にします。

f:id:hiyokosabrey:20210828125017p:plain

 

揺れるゲージは以上です

こんな揺れで満足できないという方はぜひいろんな手法を試す冒険に出かけてみてください。

一応オマケとして、配列を使った揺れの一例を紹介します。

XY座標の2軸を扱うので、Vector2D型の変数を配列で用意します。

f:id:hiyokosabrey:20210828130210p:plain

この配列から順次取り出してやります。

f:id:hiyokosabrey:20210828130410p:plain

配列の数と、カウント数の判定に注意。

これでランダムならではの不安定さはなくしつつタイムラインを使わなくてもいい感じにできます。

 

この配列に、若干のランダム値を加えると連続した際にワンパターン感が減らせます。

f:id:hiyokosabrey:20210828131146p:plain

配列から取り出した値に -3.0 ~ +3.0 の揺らぎを与えるカタチになります。

 

f:id:hiyokosabrey:20210828121816g:plain

 

 

 

バフ・デバフ等でエフェクトが乗るやつ

f:id:hiyokosabrey:20210828131625g:plain

ゲージに影響がある ステータス異常であることをプレイヤーにわかりやすく伝えるための表現として古くから親しまれているやつです。

その昔、シェーダーがまだ使えなかったころは、数種類のパーツを適宜差し替えたりしていました。

ナウい今はモダンに1パーツでやってみます。

今回作った状態変化対応は 毒状態と自動回復の2種。

 

色だけだと伝わりにくいので、テクスチャを用意しました。

f:id:hiyokosabrey:20210828151431p:plain

サイズはちょっと小さめに 64x64px  シームレスになっています。

Photoshopだとパターンプレビュー機能を使うと作りやすくなります。

エンジンにインポートして GrayScale として扱います。

 

ゲージのカラーについては、前回の記事でも紹介したカーブアトラスを使ってゲージのカラーを3本用意して使っています。

 f:id:hiyokosabrey:20210828151935p:plain

 

キモになるのはマテリアル。

f:id:hiyokosabrey:20210828150019p:plain

(※ゲージのMAX値が伸びない想定です)

Panner ノード使って常時スクロールアニメーションをさせています。

f:id:hiyokosabrey:20210828152846g:plain

Multiplyノード は ピクセルの値を 掛け算します。白=1.0 黒=0.0

白は変化しません。

 

f:id:hiyokosabrey:20210828152901g:plain

Add ノードはピクセルの値を加算します。黒は変化しません。

この 2つのカラーを振り合分けているのが Lerp (Linear Interpolate)ノード。

f:id:hiyokosabrey:20210828153625p:plain

ScalarParameterノードをつないで、 0 か 1 を受け取るようにします。
f:id:hiyokosabrey:20210828153930p:plain

 

通常時のカラーとの切り替え。

これも Lerp ノードのお世話になってます。

f:id:hiyokosabrey:20210828161801p:plain

ScalarParameterで 0~1.0 で切り替えます。

 

ゲージの長さは、Step ノードを利用して可変できるようにします。

f:id:hiyokosabrey:20210828154658p:plain

このパターンはマテリアルを使うゲージの場合よくお世話になってます。

3つのパラメータ(ScalarParameterノード)を仕込みました。

 

TypeSwitch ・・・ 0=デバフ / 1=バフ

Fade ・・・ 通常ゲージとのフェード

Value ・・・ ゲージの長さ

 

フェードアニメーションを用意します

UMGのタイムラインからマテリアルのアクセスはちょっと分かりにくい操作になります。

f:id:hiyokosabrey:20210828164555p:plain
アニメーションを追加→① して適当にリネーム →②

ゲージ本体の Image をヒエラルキーから選んだ状態で +Track ボタンを押す →③

選んだゲージ本体の Image の名前が出てくるので選択 →④

 

選ばずに +Track ボタンを押すとこうなります。

f:id:hiyokosabrey:20210828163908p:plain

All Named Widget にマウスオーバーすると一覧が出るので、そこから選択してもOK。

 

選んだ Image が追加されるので、右にある+Trackボタンをクリック →⑤

Materialsの Beush.Brush Material を選択 →⑥

f:id:hiyokosabrey:20210828164617p:plain

トラックが追加されるので同様に右にある +Parameterボタンをクリック→⑦

マテリアルのパラメータ一覧が出てくるので、Fade を選択 →⑧

f:id:hiyokosabrey:20210828165242p:plain

これでようやくタイムラインにキーが打てるようになりました。

f:id:hiyokosabrey:20210828170804p:plain

Details(詳細)タブから数値を触れないので、このタイムラインエディタからキーを編集します。

 

キャンバスの編集はここまでになります。

 

さっそくWidgetブループリントに組み込んでいきます。

マテリアルをゲージ本体の Image にセットしたら、ブループリントからマテリアルにアクセスするために、ダイナミックマテリアルインスタンスを作るようにノードをつなぎます。

f:id:hiyokosabrey:20210828162216p:plain

Return Value ピンから変数に昇格(Promote to Variable)しておきます。

 

バフ・デバフがかかった際に呼び出されるカスタムイベントを用意します。

f:id:hiyokosabrey:20210828212040p:plain

マテリアルのパラメータをセットするだけのイベントです。継続する系の演出については、発動時のタイムラグは不要なので即時見た目をチェンジします。派手にアピールする場合は、トッピング的に煙やスパークなどのエフェクトを乗せるといい感じになります。

2種類しかないので、ひとまずブーリアン型の入力を受け取るようにしています。

Select Floatノードで、True なら 1.0、 False なら 0.0 になるようにしています。

 

あとは バフ・デバフが解除された際のフェードアニメーションを再生するカスタムイベントを用意したら編集完了です。

f:id:hiyokosabrey:20210828212917p:plain

ゲージWidgetができたので、テストしてみます。

 

 

レベルブループリントでキー入力をトリガーにします。

バフ・デバフを切り替えるためのイベントを2つ用意するのが面倒だったので、ブーリアン型の変数を一つ追加して、フラグとして利用することにします。

Xキーを押すたびに、バフとデバフが切り替わります。

Zキーを押すとデフォルトの見た目に戻ります。

f:id:hiyokosabrey:20210828213331p:plain

f:id:hiyokosabrey:20210828131625g:plain

表現したい種類が増えるとそれなりに対応が変わりますが、マテリアルを改造してパラメータを増やすと、より汎用的に扱えるようになって拡張性がアップできます。少々作りがややこしくなるので今回はここまでにします。

 

 

変わり種ゲージ

f:id:hiyokosabrey:20210828214516g:plain

レベルメーターぽいやつ

動きは特にないのですが、ゲージの方向が縦になったのと、段階的に変化するのが特徴のゲージです。横のものが縦になったという劇的な概念的変化をもって動きをつけたというか、まぁ平たく言えばついでです。ちなみに漢字を使うと 「序で」と書きます。

 

さてさて

これもマテリアルで作りますが、まずはテクスチャ。

64x256px のテクスチャに、パスでラインを置いていきます。

f:id:hiyokosabrey:20210828220541p:plain

10px間隔で全部で 25Lines

ゲージ本体用と少し大きくした下敷き用の2枚用意しました。

f:id:hiyokosabrey:20210828215908p:plain

エンジンにインポートして GrayScale として扱います。

 

次にグラデーション。

カラーはカーブアトラスを利用します。

f:id:hiyokosabrey:20210828222544p:plain



マテリアルを用意します。

レベル 0~25 までのFloat値を受け取る仕様。

f:id:hiyokosabrey:20210828222822p:plain

1レベル分の高さが10ピクセルで、テクスチャの縦方向の解像度256ピクセル

10/256 を 受け取った値に対して掛けることで、ゲージの閾値が決まります。

このゲージは下から上に向かって伸びるゲージなので、1-x (OneMinus)ノードを使っています。

 

 背景の作り方によりますが、このゲージは色を変えることで増減の変化を見せるようにしています。アルファ値はテクスチャを使用しています。

このテクスチャアルファにStepノードの値を乗算するようにすると、色を変えずにOpacityで削れます。

 

キャンバスに下敷きのテクスチャと、マテリアルを配置します。

f:id:hiyokosabrey:20210828231320p:plain

下敷きテクスチャは、カラーを暗くして、本体のマテリアルの下に敷します。

 

Widgetブループリントでは ↓このように 0~1で管理している値を x25 してマテリアルに渡しています。

f:id:hiyokosabrey:20210828230711p:plain

この辺はゲームの設計に合わせて構成を変えることになると思います。

 

これで完成です。

上限が増えない想定ですが、ゲームシステム上の最大値分をテクスチャで用意しておき、表示する際にレベルの未達部分をマスクするように作るとゲージの成長が表現できます。

 

 

最後に

今回は以上の3本です。いかがでしたでしょうか。

まだまだいろんなタイプというか仕様のゲージがあると思いますが、もとは UE4イベント ぷちコン 制作への応援として書こうという動機だったので、あまりニッチなゲージを作ってもややこしくなりそうだし、そもそも読む気も失せるだろうということで、HPゲージを作ろうシリーズはここまでにしておきます。

今まで作ってきたゲージの長さを全て足すと月まで行けるんじゃないかと思ってみたりもしていますが、そもそも実寸がないので計測不能でした。ゲームともに進化するゲージ。人類が海の底で暮らすようになり視力を失わない限り恐らく永遠にゲージは無くならないだろうと思います。なんか無理やり壮大な話に持っていこうとしていますが、しんどくなってきたので、少しでもゲージづくりの魅力を感じてもらえれば幸いと願いながら筆をおくことにします。

 

 

ではでは

すてきなゲージライフを!

 

 

HPゲージをいろいろいじってみよう ー 見た目を工夫する

 ゲージのデザインは、ゲーム進行においてとても重要な役割なのに、UIの主役には絶対なれないし、主張するとウザがられ、空気読めよ邪魔だよとか言われて面積を大きくとれなかったり、え?いつの間に体力ゼロ?なんで?今の攻撃結構減ったな、ヤバい!回復しないと!などなど、細い見た目でもそれなりに情報量を込めないといけなかったりと、とても悩みどころが多いです。

そのくせ、 ただの棒じゃん、そんなの秒でつくれるんじゃね?とかもっとカッコよくして、安っぽくならないようにして、とか気軽にコメントされると切なくなります。

 

 この安っぽくならないように というのが結構重要で、ゲージに手を加えてないゲーム画面はどうしても「仮感」(システム上必要になったのでとりあえず置いてみたけどまだゲーム画面に馴染めてなくて仮っぽく見える感覚)が漂ってしまいます。見た目に情報強度はめちゃくちゃ強いのですが、立ち位置がそこじゃない感(メタ視点から見て)が滲んできて開発途中な印象を与えかねないので、開発終盤ではそれなりに手を入れられるとクオリティアップにつながります。

 

 最近は、ゲームグラフィックの描画スペックが上がって、画面情報量も格段に増えているので、そこに埋もれないようなUIを考えると、フラットデザインは結構フィットしている印象です。逆にUIに色を使わずシンプルにシルエットと位置、動きで勝負するので、デザインも実装もなかなかの難易度になってると思います。

 

 とはいえ、ゲームの世界観にふさわしいUIデザインというのがゴールなので、トレンドも意識し通つつ、『色・カタチ・動き』に意味を与えながら試行していくしかないですけどね。

 

 前置きが長くなってしまいましたが、一応続きの記事になります。

limesode.hatenablog.com

limesode.hatenablog.com

 

 UE4でゲージを作る記事は探すとそれなりに出てくる今日この頃。いまさら感が否めないのを気にしつつ、今回はちょっと切り口をかえて書いてみようと思います。

 

 ゲージは実にいろんな作り方があって、どの方法が正解とかないのですが、あるとしたら処理負荷の少ないエコなつくりで見た目がいい感じ、あたりでしょうか。

フワッとした言い方しかできないので、提案になってしまいますが、ざっと眺めてもらって試してみたいのが見つかればいいな。

 

INDEX

 

 

テクスチャ作るのめんどい

そろそろ仮UIを脱したい。でも今はまだデザインに時間を割きたくない。ちゃちゃっとエンジンコンテンツだけでどうにか。デザイナーに依頼かける前に検証。というような状況を想定。

 

カーブアトラスでちょっとリッチに見えるグラデーションゲージ

カーブアトラスと書きましたが、実際はカーブをカラーとして格納したテクスチャということになります。グラデーションは別途カーブアセットを使って作ります。

コンテンツブラウザで右クリックして Miscellaneous > Curve を選択。

f:id:hiyokosabrey:20210823223631p:plain

Curve を選択すると、ポップアップが出るので、CurveLinearColor を選択。

f:id:hiyokosabrey:20210823224213p:plain

カーブエディタが開くので、RGB各チャンネルにカーブをつけていい感じのグラデーションを作ります。

f:id:hiyokosabrey:20210823230648p:plain

 

保存したら、次にカーブアトラスを作って編集します。

f:id:hiyokosabrey:20210823230913p:plain

テクスチャサイズはデフォルトで 256 になっています。ちょっと贅沢なのでメモリ節約のため小さくします。べき乗サイズがオススメなので、 32、64、128 あたりで。

すぐ下、Gradient Curves のところに + ボタンがあるので、ここに作ったグラデーションカーブをセットします。

f:id:hiyokosabrey:20210823231408p:plain

これを保存して準備完了。

 

続いてマテリアルを用意します。

コンテンツブラウザで右クリック > Material

エディタを開いたら、さっそくカーブアトラスを扱うノードを取り出します。

f:id:hiyokosabrey:20210823231659p:plain

CurveAtlasRowParameter ノードです。

f:id:hiyokosabrey:20210823231909p:plain

ノードを選択して、Detailsタブで、カーブとカーブアトラスをセットします。

f:id:hiyokosabrey:20210823232112p:plain

セット完了したら、その他必要なノードを以下のようにつなぎます。

f:id:hiyokosabrey:20210823232248p:plain

Mask(R) は  Component Mask ノードの Rチャンネルのみ有効にした状態。

 

あとはこのマテリアルを保存して、UMGのHPゲージにセットするだけ。

テクスチャをセットする場所に、マテリアルがセットできます。

f:id:hiyokosabrey:20210823232742p:plain

カラーはまっ白にしておかないと、乗算されてカラーが思った通りに出ないので注意。

f:id:hiyokosabrey:20210823233151g:plain

ここから少し改造

グラデーションの向きを縦にしてみます。ComponentMaskを R → G に変えるだけ。

f:id:hiyokosabrey:20210823233355p:plain

 

f:id:hiyokosabrey:20210823233559g:plain

 

手っ取り早く上下反対にしたい場合は OneMinus ノード

f:id:hiyokosabrey:20210823233755p:plain

Mask(R) に使うと 左右反転します。

計算が増えるので、最終的にカーブエディットで解決するのをおススメします。

 

ここで、もうひとネタ

 

カーブを追加します。

f:id:hiyokosabrey:20210823234519p:plain

両端がグレーで真ん中が真っ黒です。

 

カーブアトラスに追加登録します。

f:id:hiyokosabrey:20210823234716p:plain

 

これをマテリアルで合成します。

f:id:hiyokosabrey:20210823234938p:plain

こんな感じになります

f:id:hiyokosabrey:20210823235206p:plain


さらに おまけでこんなカーブ

f:id:hiyokosabrey:20210824000410p:plain

これ色として使ってなくて・・・

f:id:hiyokosabrey:20210824000549p:plain

こうなります

f:id:hiyokosabrey:20210824000732p:plain

赤をハイライト、緑をシャドウとして合成しています。

 

テクスチャを使わなくてもリッチな見た目をつくることができます。



 

 

グラデーションゲージを活かしたピンチな点滅

カーブアトラスでもうひとネタ絞り出しました。

以下のようなグラデーションを用意します。

f:id:hiyokosabrey:20210824003531p:plain

 

ゲージ本体のマテリアルを複製して下敷き用のマテリアルを用意します。

タイマーとサインカーブで点滅させています。

f:id:hiyokosabrey:20210824003634p:plain

点滅のための単色グレー(図の一番上にあるノード)は、グラデーションのグレー部分と同じ明るさです。

f:id:hiyokosabrey:20210824004030g:plain

常に点滅はしているのですが、ある程度減らないと見えてこない仕様です。
特に残り体力の判定等はしていないので、どの辺でヤバみを主張するかは、カーブで調整できます。

 

 

  

テクスチャ用意できた

ただの棒はイヤだ!なんとかしてテクスチャを用意するぜぇ!せっかくテクスチャが用意できたんでなんかこういい感じの・・・、という状況を想定。

 

定番のフレームを載せるやつ

f:id:hiyokosabrey:20210824133929p:plain

説明用にちょっと贅沢な作りですが、フレーム(上)とゲージ本体(下)の2枚。

重ねやすさを優先して余白が多めです。

 

これをインポートして、ゲージ本体用のみマテリアルに持っていきます。

コンテンツブラウザでインポートしたテクスチャアセットアイコンの上で右クリックするとラクに取り込めます。

f:id:hiyokosabrey:20210824135104p:plain

f:id:hiyokosabrey:20210824141813p:plain

stepノードを使って、ゲージの長さを塗り分けています。

こういったテクスチャを使った自由な形状のゲージは、余白があるため、テクスチャの端から端までを使ってデザインされていないことがほとんど。

そこで大事な部分。

f:id:hiyokosabrey:20210824142115p:plain

ゲージとして扱うときに 0で空っぽ、1.0で満タン というのがよくあるケース。というかグラフィックで表現するときに効率的な扱い方。

同じように扱おうとすると、ゼロになってないのに、ゲージの見た目は空っぽ。満タンじゃないのにゲージの見た目は満タンということが起こります。

f:id:hiyokosabrey:20210824155401p:plain

そこで、Lerp(Linear Interpolate)ノードを使って 0 ~ 1 に補正します。

 

例えばテクスチャの幅が 512px で左端から 8ピクセル余白があったとします。

すると、 8 ÷ 512 = 0.015625 付近の数値が Lerpノードの A になります。

同様に右から 12ピクセル余白があったとしたら、

(512-12) ÷ 512 = 0.9765625 付近の数値がLerpノードの B になります。

 

電卓で計算してもよいですが、UE4は直接計算式を入力できるので便利。

f:id:hiyokosabrey:20210824160818p:plain

入力してEnterキー押したら、どこか別の場所をクリックすると計算結果に変わります。

f:id:hiyokosabrey:20210824160827p:plain

テクスチャの解像度と余白の取り方によって数値が違ってくるので、実際の表示を確認しながら微調整します。

スカラーパラメーターノード Value の値に 0 と 1 を入れて加減します。

 

ゲージの増減をマテリアルで行うので、ブループリントからマテリアルにパラメータを渡すための準備が必要です。

 

f:id:hiyokosabrey:20210824161632p:plain

Dynamic Material Instance を作成して変数に昇格(Promote to Variable)

これに対してSet Scalar Parameter Value ノードを使って数値を渡します。

f:id:hiyokosabrey:20210824162111p:plain

この関数は、前の記事で作ったものの使いまわしです。

 

f:id:hiyokosabrey:20210824162651g:plain

 

デザイン性が高くオリジナリティが出しやすいのですが、ちょっとだけ扱いが面倒になるのが難点。

 

 

 

キャラ絵を使ったゲージ 

f:id:hiyokosabrey:20210824170051p:plain

頑張って描きました。これをマテリアルでゲージにします。

f:id:hiyokosabrey:20210824170821p:plain

四隅がもったいない作りですが、実装スピードを重視してます。描画負荷がキビシイ場合は45度回転しておくという手がありますが、ピクセルが若干荒れるので解像度と相談になります。

 

 これもゲージの増減をマテリアルで行うので、ブループリントからマテリアルにパラメータを渡すための準備が必要です。

f:id:hiyokosabrey:20210824161632p:plain

Dynamic Material Instance を作成して変数に昇格(Promote to Variable)

これに対してSet Scalar Parameter Value ノードを使って数値を渡します。

f:id:hiyokosabrey:20210824162111p:plain

この関数は、前の記事で作ったものの使いまわしです。

 

できたのはこれ

f:id:hiyokosabrey:20210824172255g:plain

 

 満タン ←→ 空っぽ の変化の向きは、UとVの計算をちょっといじってやると変えられます。画像を回転する場合は効果ないですが、画面内の位置が決まってから、絵の感じ、視線の流れを見て選択するといいと思います。

OneMinusノードの使い方がポイント

f:id:hiyokosabrey:20210824174843p:plain

f:id:hiyokosabrey:20210824174857p:plain

f:id:hiyokosabrey:20210824174906p:plain

f:id:hiyokosabrey:20210824174915p:plain




 

 

 

キャラ絵の一部を切り出して使う

どこか別の場所でアイコンなどで使っているテクスチャを流用します。

これは直接ゲージにするのではなく、ゲージに重ねて使います。

 f:id:hiyokosabrey:20210824173536p:plain

この彩色されたテクスチャを加工します。

f:id:hiyokosabrey:20210824182610p:plain

 複数キャラの切り替えを想定していて、切り取る位置だけを変えられるようにスカラーパラメータにしてあります。

このマテリアルをマスターにして、あとはキャラごとのマテリアルインスタンスを量産すると、絵に合わせた素材が簡単に用意できます。

 ネガポジ反転したみたいになっていますが、これに着色してゲージに後乗せするといい感じになります。

f:id:hiyokosabrey:20210824183148p:plain

 

 

f:id:hiyokosabrey:20210824183437g:plain

 

 

 

 

 

 ひとまずこの辺にまでにしておきます。テクスチャ作成とマテリアル作成については、作る人のスキルに依るところが大きいのと、テクスチャ制作はエンジン以外のエディタ環境が必要だったりで、説明が難しいのがもどかしいですね。うまくフィットするのがあればぜひ試してみたりアレンジしてください。同じような表現でも違うアプローチで作ることができたりするので、ゲージ作りは奥が深いです。

 UMGを使わないという選択肢もあります。ただ、これは見た目のコントロール難度が格段に上がるので、3D描画の仕様にある程度慣れてないと調整に大変時間がかかります。

 逆にUMGのほうが慣れるの大変そうという方は、テキスト表現だけをUMGにして、あとはMeshで、というのも可能です。アンリアルエンジンでは使う人次第で、いろいろな作り方ができるのも魅力のひとつです。

 

 操作についてはかなり端折っているので、わからない点やツッコミ等々あればTwitterかブログコメントでお気軽にお尋ねください。レスポンスは速いとはいえないですが対応します。

 

次回はちょっと特殊な演出で遊んでみようと思います。

ではでは

すてきなゲージライフを!

 

 

 

HPゲージをいろいろいじってみよう ー 成長するゲージ

 先日公開した動くHPゲージをもっと触っていこうという内容です。

 

limesode.hatenablog.com

この記事で作ったゲージを元にいろんなアレンジや機能を試していきます。

 

UE4の最新バージョン 4.27 がリリースされましたが、この記事シリーズが終わるまでは 4.26 で進めます。

 

 

ゲージ全体の長さを変更できるようにする

キャラのLVアップや、アイテムゲットなどでゲージの上限が増えるとプレイに対しての報酬になりモチベーションのアップにつながります。

まず準備として、キャンバスに配置したゲージの長さを変数に入れて基本の長さとします。

キャンバスに配置した状態を取得してそのまま変数に保存します。

f:id:hiyokosabrey:20210820233859p:plain

サイズを入れておく変数は、Get Size ノードにある Return Value ピンから 右クリックして作るとラクです。型は Vector2D になります。

この仕組みのおかげで、キャンバスに置いたゲージの形はいつでも自由に感覚的にいじっても大丈夫になります。画面デザインの調整のたびにブループリントを調整する必要はありません。

 

Slot as Canvas Slot ノードは Image が持ついくつかのパラメータの中でも Canvas Slot というカテゴリにアクセスするときに使うキャスト系(型変換)ノードです。

 

Scale で長さを変更するというのは、画面に描画する際に掛け算してから描くということになります。その掛け算の元のサイズが、 Canvas Slot のSize になるのです。

f:id:hiyokosabrey:20210821102851p:plain



ということで、サイズを変更するためのカスタムイベントを用意します。

growGaugeと命名

f:id:hiyokosabrey:20210821011813p:plain
引数として、最新のHPと、最新の増分を受け取るようにしています。

増分、増えた分は、パーセント(%)で管理する想定。

 

ゲージは Image を2枚重ねているので、それぞれを処理しますが、Set Sizeノードには同時にいくつもつなぐことができます。。

 

真ん中左付近の見慣れないノードは ↓ こうやって作ります。

f:id:hiyokosabrey:20210821004126p:plain

いろいろ計算して、最後にゲージの長さをセットする関数をつないでいます。ゲージの上限が増えるだけなので、ゲージの長さが変化しない想定です。

f:id:hiyokosabrey:20210821004943g:plain

Sizeを変更すると、ゲージの基本の長さを伸ばすことになるので、Scaleで縮めているだけのゲージは一緒に伸びてしまいます。そこで下敷きのみが変化しているように見せています。

例えば ゲージが60%の状態で、長さが 20%増えた場合。

f:id:hiyokosabrey:20210821010602p:plain

 

この補正処理はあくまでも表示バグ対策です。

ゲームの仕様次第で変わってきますが、ゲージ全体の長さが変わったとき、その時点でのHPの量が変わらないのであれば、見た目に長さが変わるのはおかしいという理屈です。

 

ということで、テスト用のレベルブループリントも、もう少しちゃんとしようと思います。

前回の記事で MyHP という名前の Float型の変数で、ゲージの長さを比率で管理していましたが、ゲーム的に扱いにくいので、Integer型の変数を使った管理方法に変更します。

最大値も必要なので、2つの変数を用意します。HP と MaxHP と命名

f:id:hiyokosabrey:20210821130802p:plain

右下の方にあるGet Gauge HP ノードは関数です。

内容は ↓ このようになってます。この後 数か所で利用するので関数化しました。

f:id:hiyokosabrey:20210821131021p:plain

引数を受け取らず、計算結果を返すだけの内容なので、ピュア型というカタチにしています。

f:id:hiyokosabrey:20210821131302p:plain

f:id:hiyokosabrey:20210821131504p:plain

ピュア型にすると、ちょっとだけノードの流れ(白いライン)が短くできます。

 

カーソルキーの増減処理のところも変更します。

f:id:hiyokosabrey:20210821132108p:plain

ここまで改造で、前回の動作はキープできました。

 

次にようやく今回のネタの部分、ゲージの長さを変えるためのトリガーになる処理。

f:id:hiyokosabrey:20210821132819p:plain

キーボードの Bキーを押すと 50ずつHPが増えていき、その都度ゲージWidgetに補正後の割合と、ゲージの増分を割合にして渡しています。

f:id:hiyokosabrey:20210821133609g:plain

 

このゲージの上限が増える表現については、ゲームの仕様によってさまざまなスタイルがあります。

いつどのタイミングで増えたことを見せるか、というのが設計のときに大事になります。

ちなみに ゲージの最大値が増えると、安心感が増える一方で難易度が下がったり、緊張感が減ったりするので、用法容量にはご注意ください。

 

 

 今回はここまで

次回は見た目を工夫してみようと思います

 ゲームの数だけゲージデザインがあるので助けになるかわかりませんが、ヒントになれれば幸いです。

 

ではでは

すてきなゲージライフを!

 

  

 

 

 

 

おまけ

UMGのチュートリアルでゲージといえば、プログレスバーを使ったゲージが紹介されていることが多いかと思います。

f:id:hiyokosabrey:20210821092126p:plain

f:id:hiyokosabrey:20210820224840p:plain

すでにこのProgressBarコンポーネントでUIを作られている場合でも、前回の記事を利用できます。

前回の記事ではImage のスケーリングで長さを変更していました。

その際の関数内の編集のみでサクッとプログレスバーに差し替えることができます。

 

f:id:hiyokosabrey:20210820225422p:plain

↑これを
↓こうします

f:id:hiyokosabrey:20210820225246p:plain

編集完了。

 

f:id:hiyokosabrey:20210820230005g:plain

 

動くHPゲージを作ってみませんか

季節は残暑。まだまだ真夏のはずですが、ここ最近の空模様のせいかセミの声も遠く感じる今日この頃いかがお過ごしでしょうか。先日のクイズゲームの記事でちょっとばかり燃え尽きてたりして間が空いてしまっていました。参加しそびれたのですが、ぷちコンのエンドレスランを作るイベントを見て、何か自分もぷちコン制作のお役に立てるものがないかと考えた結果、ゲージについて書くことにしました。

今までも度々ゲージに触れてきましたが、エンジンもずいぶんアップデートされてますし、復習もかねて記事にしてみようと思います。

 

UE4の基本的な操作方法については、「まぁまぁできるよ」という方を想定していますが、わからない操作等あれば、みつまめ杏仁 (@MMAn_nin) | Twitter かブログコメントにて問い合わせいただければ対応します。

 

 

  

 

シンプルなゲージとはいえ

ゲージが減った時に パッ、パッ、と途中段階のアニメーション無しに変化するタイプ。作るのは比較的易しいですが、常にゲージを見つめながらプレイは無理です。どれだけ減ったのか、いつ減ったのか、変化に気づきにくいので動きをつけるとグッと見た目がアップします。

f:id:hiyokosabrey:20210817001105g:plain

 

f:id:hiyokosabrey:20210817002313g:plain

 

 

今回はテクスチャを使わずシンプルなパーツで作っていきますが、増減する処理のところは、汎用的な仕組みなのでいろんなスタイルのゲージにも使えると思います。

 

 

作ってみよう

まずはWidgetのキャンバスにゲージの見た目として、Image を2つ重ねます。

f:id:hiyokosabrey:20210818012524p:plain

同じサイズで同じ位置に重ねると1枚に見せることができますが、いろいろアレンジできます。上図のように(下敷きの色が見にくいですが)ドロップシャドウぽく見せたり、下敷きを大きくしてみたり。

f:id:hiyokosabrey:20210818233049p:plain

大事なのは、後ろの背景に紛れてしまわないようにすることです。

そのためには手段を選ばないのがゲージを存在させるために必要な心意気です。

 

下敷きは、ゲージが減った状態でも、満タンからどれだけ減ったかがわかるので、とても重要な存在です。

 

上に置いたゲージを本体とします。

 

UMGで重ねた時の順番をコントロールする方法は2つあります。

ひとつはヒエラルキーでの位置

f:id:hiyokosabrey:20210819223224p:plain

もちろん後から描くほうが手前です

もう一つは ZOrder の値の大きさ

f:id:hiyokosabrey:20210819223400p:plain

数字の大きい方が手前になります。

ヒエラルキーで同階層、ZOrderの数字が同じ場合は、ヒエラルキーの順番で描かれます。またヒエラルキーで親子階層になっている場合は親同士が比較対象で、子供たちは親に依存します。

 

ゲージの長さは横方向のスケールを変えることで可変させるので、Pivot 位置を変更する必要があります。

f:id:hiyokosabrey:20210819000203p:plain

Render Transform にある Pivot X をゼロにすると、左端がスケールの基準点になります。デフォルトは (0.5, 0.5) なので、ど真ん中が設定されています。
Photoshopの変形時に表示されるバウンディングBOXをイメージするといいかも。

f:id:hiyokosabrey:20210819000720p:plain

 

Pivot X を 1.0 にすると、 右に減っていくゲージが作れます。

 

 

必要なパーツが配置できたので、ブループリントを編集します。

編集モードを Designer から Graph に切り替えます。

 

 

まず変数を2つ用意します。VariableType は Float型

f:id:hiyokosabrey:20210818234100p:plain

f:id:hiyokosabrey:20210819001546p:plain

CurrentValue と NewValue という名前にしました。

 

 

 

次にゲージの長さを変更するための関数を一つ作ります。

変数同様に、My Blueprintタブの Functions の右にある + ボタンをクリックすると新しく追加できます。

名前を changeGauge と命名して編集開始。

f:id:hiyokosabrey:20210819001726p:plain

① My Blueprintタブの Variables からゲージ本体の Image(キャンバスにレイアウトしたやつ)を取り出します。

 

② そこから Set Render Scale ノードを取り出してつなぐ

 

ここで、Scale の X だけを引数として受け取りたいので、ひと手間かけます。

f:id:hiyokosabrey:20210819002417p:plain

③ Set Render Scale の Scale ピンのところで右クリック

④ リストから Split Struct Pin を選択

 

こうなります。

f:id:hiyokosabrey:20210819002603p:plain

あとは、 Scale X のピンをドラッグ ⑤ して、 関数のノードにドロップ ⑥。

 f:id:hiyokosabrey:20210819002804p:plain

 

仕上げに 引数の名前と、Scale Y の値を変更。

f:id:hiyokosabrey:20210819003051p:plain

関数はこれで完成。

 

ちなみにピンの分解をせずに Make系のノードを使っても同じ結果になります。

f:id:hiyokosabrey:20210819224525p:plain

濃い青色のピンからドラッグして、make で検索すると取り出せます。この色のピンは特定の型を示すものではないので、慣れてないと不気味な感じですが、こうやってドラッグしてMakeノードを取り出したり、先の右クリックしてSplit(分割)する方法を使うと、中身がわかるようになってます。基本的に色の違うピン同士はつながらないのですが、これらの方法でどうにかなったりするので、馴染みのないピンが現れたらぜひ試してみてください。

 

 

つぎに EventGraphに戻って、カスタムイベントを一つ追加。

用意しておいた Float型の変数を使って計算と判定を行います。

f:id:hiyokosabrey:20210820003912p:plain

NewValue には 新しいゲージの値が入る想定。最新の結果が外から送られてきます。

CurrentValue は現在のゲージの値。

CurrentValue と NewValue に差分が発生するとアニメーションさせます。

差がなくなるとアニメーションは終了です。

アニメーションは簡単な減速処理です。イーズアウト的な動きになります。

左の方にある 0.25 という値を小さくするとゆっくり、大きくすると素早く動くようになります。

 

詳しくは過去記事で解説しているのでそれを貼っておきます。

Widgetで追跡するカーソル - みつまめ杏仁 (hatenablog.com)

 

続きの部分

f:id:hiyokosabrey:20210819013030p:plain

ここで、作っておいた関数を呼び出して、変化した変数を見た目に反映しています。

 

この計算式では、Current~とNew~が限りなくゼロに近づくだけでゼロにはなりません。

0.00000000001.....  みたいな感じで桁が増えていくばかり・・・

NewValue と CurrentValue の差がゼロになったら、 つまり 同じなら、というのを厳密にやると、一向に終わらないということになります。

そこで

Nearly Equal(Float) ニアリーイコールノードを使って、もういいだろうという範囲まで来たら、ゼロとみなすという判定を行っています。

 

Set Timer by Event ノードは、 指定した時間が経過したらイベントを呼び出してくれるノードです。

前のカスタムノードにつないでいるので、NewValue と CurrentValue の差が埋まらない限りは、何度でもカスタムイベントを呼び続けます。

 

これでエンジン的な処理が完成しました。

 

仕上げに、このイベントを始動するカスタムイベントと、ゲージを初期化するイベントを作ります。

 

新しくカスタムイベントを用意します。

f:id:hiyokosabrey:20210820004044p:plain
右端のノードは先に作った増減アニメーションのカスタムイベントを呼び出すときのノード。

 CurrentValue はこのWidget内だけのもので、外からNewValueに対して値を更新してもらうのが今回の仕様です。

 

ほぼほぼ完成ですが、ゲームをやり直したりする場合にゲージをリセットする必要があります。またコンティニューでその場復活HPちょっとだけ回復とか、あったりするので、アニメーション無しに一瞬でゲージの長さをセットしてしまう処理を用意しておくとゲーム的に何かと都合がよかったりして便利です。

そこでこのカスタムイベント。

f:id:hiyokosabrey:20210819231629p:plain

 

これでゲージのWidgetは完成です。

 

ぼくの場合Widgetの表示は、HUDクラスに担当してもらうのですが、手っ取り早くテストするために、レベルブループリントで試します。

 

テストする

ゲージ用の変数を一つ追加します。とりあえず MyHP と命名

ゲームにおけるHP管理用に相当します。

 

Create Widget ノードを取り出して、作ったゲージ用Widgetをセット。

f:id:hiyokosabrey:20210819232415p:plain

Return Value のピンから 変数に昇格(Promote to Variable)させて UserWidget型の変数を作ってつなぎます。

あとは、Add to Viewport ノードで画面に描画、HPの初期値をセットして、ゲージWidgetの カスタムイベントを呼び出します。

 

この状態で、任意の長さのゲージが表示できます。

 

次にキー操作で増減させます。

input ノードを使います。

Left と Right は それぞれカーソルキーの左右です Left[←] Right[→]

f:id:hiyokosabrey:20210820002116p:plain

二つとも内容はほぼ同じなので、片方を作って複製するとラクができます。

違うのはここ↓(緑の部分は上と同じ)

f:id:hiyokosabrey:20210820002618p:plain

これで再生してみると、カーソルの左右キーを押すたびに、ぎゅんぎゅん動くはずです。

f:id:hiyokosabrey:20210820003251g:plain

減るだけじゃなく増えるのも問題なしです。

満タンと空っぽのチェックをきちんとやれば、Widgetの カスタムノード UpdateGauge を呼び出して HPの値を渡してやるだけで勝手にアニメーションします。

 

ちなみに、スペースキーでリセットする場合はこんな感じにつなぐだけです。

f:id:hiyokosabrey:20210820011347p:plain

いつでも満タンにできます。

 

ひとまず想定していた仕組みが完成したので今回はここまでにします。

次回はこのゲージを使ってアレンジを楽しんでみようと思います。

ゲームの数だけ、仕様の数だけ、ゲージがあるので、作り方や実装方法も実に様々です。

こんなゲージ作ってみたいけど作り方がわからないとか、ちょっと無茶ぶりしてやろうとかあれば、チャレンジして作ってみようと思いますので、お気軽にメッセージ等々でネタ提供をお待ちしております。

 

ではでは

素敵なHPゲージライフを!

 

 

UE4のUMGでクイズゲームができた《記事まとめ》

アンリアルエンジン4でクイズゲームづくりにチャレンジということで、約1ヶ月8回に渡って記事を書きました。ここで一覧にしてまとめておこうと思います。

f:id:hiyokosabrey:20210705001532p:plain

 

完成したクイズゲームとしての仕様

  • 複数の問題から出題
  • 選択肢は 4つ
  • 時間制限がある
  • 制限時間内に一定数正解するとゲームクリア
  • 制限時間内に一定数正解できなければタイムアップ
  • 選択肢の配置はランダム

 

UIの 素材として作るものは

  • タイトル画面
  • 共通背景
  • 出題画面
  • 正解画面
  • 不正解画面
  • タイムアップ画面
  • クリア画面
  • タイマー表示
  • 正解数カウント表示

 

 

UE4のUMGを触ったことをない方でも試していただけるように、操作についてはなるべく省略しないように書いてます。

 

 まずは《準備編》と《組み立て編》を試していただくと、

紙芝居のような画面切り替え方式で一応のクイズゲームができます。

 

UE4 の バージョンは 4.26 を使っています。

汎用的なしくみを使うようにしてるので、少し前のバージョンでも問題ないと思います。たぶん。

 

limesode.hatenablog.com

 WidgetSwitcher(ウィジェットスイッチャー)という、ストックさせた複数のWidgetを切り替えることができるコンポーネントを利用します。

《準備編》ではビジュアル素材を揃えます。画面ごとにWidgetアセットを用意するところまで。

 

limesode.hatenablog.com

《組み立て編》ではブループリントで複数の画面を切り替えられるようにします。

ボタンクリックがトリガーとなって切り替えられるようにします。

まだクイズと選択肢は固定です。

 

 

 

ここからは、ゲームとしての機能を充実させつつ、実践で役立ちそうなテクニックについて紹介しています。

 

 ただの数字にラベルを付けて扱いやすくする仕組み。

WidgetSwitcherの切り替えは数字で行うのですが、いちいち覚えていられないので、Enum を利用します

limesode.hatenablog.com

 

 UIデザインに関わる立場として、プロトタイプから本番に向けて効率のいい作業フローを模索してみた成果。

無事プロトタイプが採用された体での本番デザインの差し替えについて。

limesode.hatenablog.com

 

 よりゲームらしく。

「タイマー」を扱うための仕組み。一時停止と再開のコントロール

limesode.hatenablog.com

 

さらにゲームらしく。

クリア条件を決めるとその進捗が必要になる。記事のボリュームが大きくなったので前後編に分割。

limesode.hatenablog.com

 さらにゲームらしく。

 クリア条件ができると、失敗条件もまた必要。

limesode.hatenablog.com

 

 クイズゲームらしく。

たくさんの問題の中からランダムに選ぶ。ランダムで選ぶことの難しさと面白さ。

limesode.hatenablog.com

問題を用意するのが結構大変ですが、探してみるとクイズの問題集を公開しているサイトが見つかるので、利用できると手っ取り早く楽しめます。

 

ここまでで完成とします。

youtu.be

 

今回のクイズゲーム制作を通して、UE4でのUI制作に慣れ親しんでもらえたら、またそのきっかけになれば嬉しいです。ぜひカスタマイズやアレンジに挑んでみてください。

 

ではでは

すきな UMGライフを!

そうだ、QUIZゲームを作ろう《おまけ編》たくさんの問題

 UE4クイズゲームを作る記事の続きです

 クイズゲームなのでここで扱う「問題」はトラブルではありません。なんか、内容に問題ありな題をつけてますが、「問題だらけ」とか「問題がいっぱい」よりはマシかなぁとか考えてみたけど、あまり変わらない気もする。

 繰り返し遊ぶとなると、問題がたくさんあると面白くなります。知ってる問題が何度も出題されるとラッキーだけど、ちょっと残念な気持ちになります。クイズって、自分の知識を試す場でもあるけど、自分の知らない知識に出会う場でもあると思うのですよ。自分はこの問題について全く知らないけど、知ってる人がいるから、出題されてるんだと思うと、ちょっぴり悔しいし、へぇっていう場面もあるのが面白いです。少なからず知識欲が刺激されてるんだと思います。

 黒猫のウィズとかは買い切りじゃないからオンラインでアプデできるし、メモリが問題になるなら場面ごとにダウンロードしてもいいわけで、そうなると、メンテすればいくらでも問題を作って増やせるよな、とか思ってるんですけど実際どうなってるんでしょうかね? 

 

さてさて、

ここまでで、一通りのゲームサイクルができたと思っています。

f:id:hiyokosabrey:20210625230121p:plain

超シンプルな構成です。

あとはここにお好みで素敵な絵やストーリー、スゴロク的マップ、育成などの要素を盛り込んでいけばグレードアップ!あとジャンルセレクトとかも!

 

はい 盛り上がりもほどほどに、問題を用意してランダムに選択する仕組みを作っていこうと思います。

 

仕様は、1つの問題文に対して選択肢が4つ。テキストが合計 5つ必要です。

今回少しアレンジを加える想定です。

 

目次

 

 

ストラクチャとデータテーブル

最終的にDataTable(データテーブル) というアセットを用意するのですが、その前にStructure(ストラクチャ=構造体)を作る必要があります。

f:id:hiyokosabrey:20210625232307p:plain

MicrosoftExcel を触ったことがある方なら少しはイメージしやすいかもしれないです。

Excelは列やセルに、データの表示形式を設定できます。 「数」なのか「数」なのか入力する人がルールを決めないと判断がつかないからです。UE4のデータテーブルは、Excelでいうところの各列(A~)が変数のタイプと連動するように設計されています。

 

Structureの作り方は、コンテンツブラウザで右クリック

コンテキストメニューから Blueprints > Structure を選択

f:id:hiyokosabrey:20210626104506p:plain

f:id:hiyokosabrey:20210626105015p:plain

QuestionStruct と命名。このあと検索するので、なるべく見つけやすい名前にするといいです。

ダブルクリックして編集します。

f:id:hiyokosabrey:20210626105247p:plain

エディタが開きます。

ブーリアン型の MemberVar_0  という変数名がすでに一つ登録されています。

名前を変更して、変数タイプを Text に変えます。

f:id:hiyokosabrey:20210626105830p:plain

変数の中身は、エディタ下部の Default Value に適当なテキストを入力しておきます。

構造体というのは複数の変数を一式として扱うことができます。

New Variable ボタンをクリックします。 5回。

同じ要領で、変数の型をText に変えておきます。

f:id:hiyokosabrey:20210626110947p:plain

変数名はとりあえず A0~A4 としました。アレンジ用に選択肢を5つにしました。

これで保存します。

 

Structureが用意できたので、今度は問題と解答を用意します。

 

問題と選択肢をCSVで用意する

 問題と解答のテキストは、CSV形式でUE4にインポートします。

CSV(カンマ区切り形式:Comma-Separated Values)はメモ帳みたいなテキストエディタでも簡単に作れますが、管理するならExcelのような表組ベースのエディタが便利です。

 ぼくは Office製品を手元に持ってないので、 Googleスプレッドシートを使いました。

Googleアカウントでのログインが必要になります。

f:id:hiyokosabrey:20210626121316p:plain

重要なのが、一行目に半角英数で変数名を入力することです。

Structureの変数名と同じにしておく必要があります。

 

 左上の A1 のセルは何を入力しても無視されるので、空欄でOK。

 A列は Name型という型で扱われることになります。今回は数字で連番にしておきます。

 なお、正解はひとつなので、C列 を 正解として扱うことに決めます。D~G列は間違いとしてそれっぽい、ひっかけ的な答えを適当に用意します。

 

 ある程度数が用意できたら、これをCSV形式でダウンロードしてローカルPCに保存します。

 ファイル名に拡張子 .csv がついていればUE4にドラッグ&ドロップできます。

 適当にDLしてからインポート前にリネームしてもOK。

 メモ帳で開くとこうなってました。

f:id:hiyokosabrey:20210626123815p:plain

 カンマで区切られてるけど、間が詰まりすぎて編集しにくいですね。

 一応 Tab文字(Tabキーで入力) を入れて整形できますが、

f:id:hiyokosabrey:20210626124240p:plain

 問題文が複数行だとあまり解決できている気がしません。

 複数行の場合、改行を意味する文字が見えないので、ダブルクォート → " " でくくることで範囲を示します。

 例えば3行あるとき

f:id:hiyokosabrey:20210626130303p:plain

CSV専用のエディタがあったほうが良さそうです。

 

UE4にインポートする

 で、このCSVUE4のコンテンツブラウザにドラッグ&ドロップすると、インポートダイアログが出てきます。

f:id:hiyokosabrey:20210626145934j:plain

Choose DataTable Row Type: のプルダウンから、用意した Structure の名前を検索します。

f:id:hiyokosabrey:20210626150112p:plain

インポートが完了するとCSVと同じファイル名のアセットが誕生します。

f:id:hiyokosabrey:20210626150325p:plain

 

カンマの数が多かったり少なかったりすると、警告されます。

f:id:hiyokosabrey:20210626151353p:plain

f:id:hiyokosabrey:20210626151024p:plain

OKボタンを押すとそれなりにインポートはしてくれます。

足りないときは、初期値が入れられて、多すぎるときは、その行はスキップされます。

CSVを修正して再インポートすればキレイにインポートされます。

インポート時にエラーで突っぱねるのではなく、ひとまず事故らないようにインポートしてくれるのはありがたいですね。

 

インポートしてできた DataTableを開いてみましょう。

f:id:hiyokosabrey:20210626155929p:plain

上の Reimport ボタンで、CSVファイルを何度でも再読み込みできます。

CSVファイルを更新したら、毎度 Reimport → Save という操作が必要です。

このエディタを開かなくても、コンテンツブラウザ上でもできます。

f:id:hiyokosabrey:20210626173721p:plain

再インポートがうまくいくと、右下から表示が現れて成功を知らせてくれます。

f:id:hiyokosabrey:20210626173826p:plain


また、このエディタからデータの追加や編集が可能です。

 

いまのところ改行の方法が見つけられていません。\n みたいな改行文字を入れておいて別途置換する方法を使えば1行で書いてしまうこともできますが、今回は問題を増やしやすくするために外部のエディタをオススメしておきます。

Googleスプレッドシートなら思いついたときに出先からでも追加できますしね。

共有すれば共同作業も可能です。インポートの手間はかかるけども、外部のエディタで作業するのはバックアップを取りやすいのもメリットじゃないかなと。

 

f:id:hiyokosabrey:20210627150848p:plain



 

 DataTabeleが保存できたら、あとはブループリントから読みだして表示してやるだけです。

 

データテーブルを読む関数

 クイズ本体の wb_Mainを編集します。

f:id:hiyokosabrey:20210626211141p:plain


 新しい関数を作ります。

 編集モードを Graph にして、My Blueprint の Functions から +ボタンをクリック。

f:id:hiyokosabrey:20210626211256p:plain

 関数名は getQuestionInDataTable と命名

 

関数を編集していきます。

getDataTableRowノードでDataTableへアクセスします。

f:id:hiyokosabrey:20210626212844p:plain

f:id:hiyokosabrey:20210626212833p:plain

 DataTable ピンのところに、用意したDataTableアセットをセットします。

 

 Row Name のピンには、数字を渡して中身を引き出すのですが、Name型というタイプじゃないと受け付けてくれません。

 

 今回は 番号 でクイズの問題を管理しているので、キャスト(型変換)が必要になります。

f:id:hiyokosabrey:20210626214054p:plain

 キャストには しりとりのように順番があります。

 数値 → 文字列 → Name型 の流れです。

 

 逆から進めると少し手間が減るので下の画像は逆引きでつないだ場合です。

f:id:hiyokosabrey:20210626212539p:plain

 関数のInputsピンを追加してからでも問題ありません。

 

 これで整数を使って任意のクイズを取り出すことができます。

 

 取り出したクイズは、 青い Out Row ピンから出力されます。

 そこから ドラッグして Breakノードを取り出します。

f:id:hiyokosabrey:20210626215504g:plain

 Breakノードはストラクチャ(構造体)の中身を個別に取り出せるようにするノードです。ちなみにストラクチャに戻すのは Makeノードになります。

 

 Structureで設定したピンがずらりと並びます。

 この内容を保持するために、この関数専用のローカル変数を追加します。

 関数編集中にのみ現れる Local Variables から +ボタンを 3回。

f:id:hiyokosabrey:20210626220800p:plain

 Text型、Boolean型、Integer型の 3つ。

f:id:hiyokosabrey:20210626221135p:plain

 Text型とBoolean型は配列にします。

 Variable Type の 右端にあるアイコンをクリックすると、小さなリストメニューがポップします。

f:id:hiyokosabrey:20210626221541p:plain

 9マスのグリッド状のアイコンが配列です。

 

 名前に  temp_ と付けているのは、一時的なという意味の temporary(テンポラリー) の略です。

 関数が呼び出されるたびに作られて、関数の処理が終了すると破棄されます。

 刹那的な変数なので関数の外に持ち出すことができません。

 

 この一時的配列変数をグラフにドロップして、Add ノードを取り出します。

f:id:hiyokosabrey:20210626222729p:plain

 もう一つのBoolean型の配列も同じように Add ノードを取り出します。

 

 getDataTableRowノードの Row Found ピンとつなぎ、Breakノードの A1 ピンともつなぎます。

f:id:hiyokosabrey:20210626223008p:plain

 残りの A2~A4 のピンをつなぐために、Add ノードを複製します。

f:id:hiyokosabrey:20210626225711p:plain

 新たに3セット追加。
f:id:hiyokosabrey:20210626225933p:plain

 この灰色のノードたちに魂を入れます。

f:id:hiyokosabrey:20210626230033p:plain

 とどめに Shuffle ノードをつなぐ。

f:id:hiyokosabrey:20210626230412p:plain

 配列のGetノードは下に移動しました。

f:id:hiyokosabrey:20210626230541p:plain

 この Shuffle ノードは配列の中身を文字通りシャッフルしてくれます。

 A0 のピンは 正解で配列には含めていません。

 A1~A4 はすべて間違いなので、どれだけシャッフルしても何の問題もないのです。

 

 次に、正解を上書きするためのランダムな値を作ります。

f:id:hiyokosabrey:20210626231442p:plain

 Random Integer ノードは 0 ~ Max-1 の間でランダムな値を生みだします。

 この配列は 4回の Addノードをつないでいるので、 Maxには  4 を指定。 0 ~3 の4面ダイスを振るイメージ。

 こうして選ばれた数字を ローカル変数に取り置きします。

 

 次に、配列の中身に対して、指定したIndex番号の中身を書き換えるのが Set Array Elem ノードです。これをつなぎます。

f:id:hiyokosabrey:20210626232410p:plain

 Item ピンのところに DataTable から取り出す A0 のピンをつなぎます。

f:id:hiyokosabrey:20210626232904p:plain

 正解を上書きする場所(Index番号)が決まったので、おなじく判定用の配列にも反映させます。

f:id:hiyokosabrey:20210626233239p:plain

 

 配列の中身が変化する流れとしては3つのステップ。

f:id:hiyokosabrey:20210627154012p:plain

 

 

 関数の最後はReturn (リターン)ノードを取り出してつなぎます。

 関数にだけ用意されているノードです。

 何もないところで右クリックして、 .  ←ピリオドで検索すると出てきます。

f:id:hiyokosabrey:20210626233736p:plain

 この Returnノードは 戻り値(もどりち)とか Return Value とかいう外に値を渡すための ピンを追加することができます。

 

 このReturnノードに、 Breakノードでバラした問題文 Qピン をドロップしてつなぎます。

f:id:hiyokosabrey:20210627111921p:plain

 ラインが重なるのと見づらいので、途中でダブルクリックしてリルートノードを使って経路を整えるのをオススメ。

f:id:hiyokosabrey:20210627112218p:plain

 あとは、配列変数を 2つを同様に Returnノードに渡します。

f:id:hiyokosabrey:20210627112503p:plain

 これで関数は完成です。

 この関数のInputs(入力) と Outputs(出力)はこのようになりました。

f:id:hiyokosabrey:20210627112736p:plain

 Detailsタブから、先に Inputs も Outputs もピンを追加しておくこともできます。

 +ボタンを押して追加するのですが、ピンの名前が NewParam みたいなテキトーな名前になります。

 ノードに直接変数からドロップすると変数名を使ってピンを追加してくれるので、小さなことですが、手間を減らしつつブループリントが分かりやすくなるのでオススメです。

 Inputs と Outputs ピンは変数の型を設定して利用します。

 これは、フィルターというかラベルみたいなものなので、変数が作られているわけではありません。古くからある知育玩具で、形を合わせないとブロックが通過できないアレに似ていますね。

 

 "temp_" とかは関数の外では不要な情報です。気になる場合は整えます。

f:id:hiyokosabrey:20210627113547p:plain

 

 

クイズを選択

 関数の編集が終了したので EventGraphに戻ります。

f:id:hiyokosabrey:20210627115627p:plain

 

 クイズを選択してセットするカスタムイベントを用意します。

 空いてるところでカスタムイベントを取り出します。名前を chooseQuiz としました。

 そこへ関数を グラフにドロップしてつなぎます

f:id:hiyokosabrey:20210627115834p:plain


この関数の戻り値(ReturnValue)を保持する変数を新しく追加します。

Variables の+ボタンから2つ変数を追加して配列にします。

f:id:hiyokosabrey:20210627120719p:plain

 この配列の中身は数が予め決まっていて、ゲームの開始から終了まで変動しないので、サイズを固定してしまいます。

 

 まず追加した2つの配列変数をドロップ。

f:id:hiyokosabrey:20210627121201p:plain

 Event Pre Construct で初期化します。

 そこに Resize ノードをつないで、値を 4 にします。

f:id:hiyokosabrey:20210627121314p:plain

 配列変数って、作っただけだと何個空きを用意するか決まっていないので、可能な限り前もって確保しておくようにします。

 

 この配列変数を、クイズ選択の関数につなぎます。

 併せて、クイズの問題文もキャンバスのTextSetTextノードでセットします。

f:id:hiyokosabrey:20210627130024p:plain

f:id:hiyokosabrey:20210627125652p:plain

 この続きに、回答ボタンへのSetTextをつないでいきます。

f:id:hiyokosabrey:20210627130411p:plain

 

 あとはこのカスタムイベントを、クイズスタートイベントのところに挿入します。

f:id:hiyokosabrey:20210627131510p:plain

f:id:hiyokosabrey:20210627131848p:plain

 これで問題文と回答ボタンが更新されます。

 

回答ボタンに配列をセット

 つぎに、回答ボタンに対して正解、不正解をセットしてやります。

今までは、正解ボタンを決めて処理してましたが、ここで配列を反映させます。

f:id:hiyokosabrey:20210627132335p:plain

 

あともう少しで完成です。

いったんコンパイルして確認してみましょうか。

f:id:hiyokosabrey:20210627133449p:plain

 回答ボタンが毎回シャッフルされています。同じ問題で答えが判っていてもそれなりに戸惑うはず。消去法に頼れなくなるやつです。これが今回アレンジとして入れたかった仕様です。

 

完成一歩手前!

 

ランダムチョイス

 最後に いっぱい考えた問題をランダムで選ぶ処理を追加します。

f:id:hiyokosabrey:20210627134020p:plain

 このピンに問題番号を渡せばいいのですが、ただランダムにすると、重複することがあります。

f:id:hiyokosabrey:20210627134502p:plain

 重複を回避する方法は いくつかあるみたいですが、今回のクイズゲームでは制限時間があり、それほど多く回答できる機会はないという想定です。

 問題の数が少ないうちは トランプ同様に 配列を Shuffle するのが簡単なのですが、問題数が多くなると、Shuffle用の巨大な配列を作る必要が出るし、処理負荷が気になります。

 なので、

 今回はランダムな値を記録用の配列に積んでいく作戦を採用します。

 このランダムな値を積むときに、重複していないかをチェックして、重複を発見すると、積むのを止めて、もう一度ランダムな値を作るところからやり直します。

 

 選択履歴を保存しておくための配列変数を新しく追加します。

f:id:hiyokosabrey:20210627164450p:plain

 SelectedQuizと命名

 これをクイズゲーム開始時に初期化しないといけないので、初期化用のカスタムイベント Initialize で CLEARノードと合わせてつなぐ。

f:id:hiyokosabrey:20210627164744p:plain

 CLEAR は 配列の中身をキレイサッパリ空っぽにしてくれるノードです。

 いろいろ履歴が積まれていてもここでお掃除。

 

 ランダムセレクト用に新しく関数を作ります。

 ローカル変数を 3つ。 Integer型(整数型)が 2つ。Boolean型が 1つ。

f:id:hiyokosabrey:20210627165721p:plain

temp_NewNum は、選択決定した問題の番号。

temp_Max は、用意した問題の最大数を意味します。

temp_isFound は、既に選んだことがあるかどうかの判定用に使います。

 

 関数の中身はこうなります。

f:id:hiyokosabrey:20210627170211p:plain

 まずクイズの最大数を受け取って、WhileLoop で最大数までのランダムな値をゲット、重複チェックをしています。

 重複がなければ選択履歴用の配列変数 SelectedQuiz に追加して完了というものです。

 

 WhileLoop ノードは、 Condition(条件)が true だと、LoopBody を実行し、false になると Loopを止めます。

 WhileLoop のセリフ

 「君 (temp_isFound) がッ false になるまで 僕は LoopBody の処理を止めないッ!」

 

 LoopBody の処理については以下のようになってます。

f:id:hiyokosabrey:20210627184844p:plain

 

今回時間制限タイプのクイズなので、制限時間が長くなって間違いを選びまくると問題数が足りなくなるのが予想されます。すべての問題を出題してしまうと無限ループになってしまいます。

解決策として思いつくのは 3つ

  • 問題数を増やす(最短時間で間違いを連打しても大丈夫なくらい用意する)
  • 間違いを選択するとタイムを減らす(ペナルティな印象が強くなるが・・・)
  • すべての問題を出題したらリセットする

安全で確実なのは、3つ目のリセット。

ということで、選択履歴用配列の数が問題数と同じになれば、CLEARするようにします。

f:id:hiyokosabrey:20210628220810p:plain

LENGTH(レングス)ノードは、配列の数を調べてくれるノード。

これで安心です。

 

 

 これで関数ができました。

 ここに挿入すればOK。

 

Max の値は、今回用意できた問題数ということで 12 を入力しています。

ここは用意できた数に合わせて変更してください。

f:id:hiyokosabrey:20210627185258p:plain

 

 編集は以上です。

 

wb_Main の全貌

※関数とマクロは除く

f:id:hiyokosabrey:20210627185652p:plain

 

  おつかれさまです。

 これで一通りの実装ができました。

 コンパイルして保存したら確認してみます。

 

youtu.be

 

完成!

 UI要素だけで完結できるゲームとしてクイズゲームをチョイスしました。なかなかのボリュームになり、途中くじけそうになりましたが、無事なんとかカタチにはできたので胸をなでおろしています。

 基本操作の説明から始まって、できるだけ現場で使える実践向きの考え方やテクニックを織り込んで記事を書いてみました。

 ビジュアルについてはあえて力を抜いています。デザイナーの方はぜひアレンジを楽しんでほしいし、画像系の作成環境に自信のない方でも進められるようにしたかったからです。どっかのストレージにアップするのも考えましたが、このぐらいのクオリティでプロトタイプがサクッと作れる、というのをアピールしたかったというのもあります。

 

 多少の手戻りっぽい修正を意図的に入れましたが、実際には試行錯誤しながら、確実に成功する方法を記事にしています。できればもっとデバッグの方法も紹介したいのですが、さすがに面白くないでしょうね。

 

 UE5が早期アクセスを開始され、世間が驚愕のグラフィックに沸いてる中、UMGを使って地味にクイズゲームを作るという、なんだかイベント会場を間違えて露店を開いたような気分になりつつも、UE5にゲーム開発の未来を見たUIクリエイター志望の方々、またUE4を初めて触る現役UIクリエイターの皆様へ、少しでもエールを送れたらなというのをモチベーションにしてここまで来れました。

 エディタの操作方法についてもなるべく丁寧に説明を書いたつもりですが、分かりにくいところや要望などあれば、お気軽にお問い合わせくだされば対応します。

アレンジのやり方なども内容次第ですがアドバイスできるかもしれません。

このブログのコメント機能(承認制なので応答まで時間がかかります)かTwitter@MMAn_nin)にてお待ちしています。

 

 

ではでは

ステキなクイズゲームライフを!

 

 

 

今回参考にさせていただいた記事

キンアジちゃんのブログ。現場で使えるテクニカルな記事満載!

kinnaji.com