みつまめ杏仁

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

雑記#20210417

今年も新人さんたちが入社してきました。去年のこの時期はいろいろとアレやコレやでもう大変でしたが、新型コロナに気を取られてもう一年が経ちました。早いものですね。まだまだ脅威は去っていないというかむしろ近づいてきてる気がするので、戦々恐々とする毎日です。UE4でもいじって心を落ち着かせるとしましょうか。小ネタですがブログに残しておきます。

 

 

 

最近Twitterにあげたやつ その1

あの最近話題の育成ゲームです。ついアニメも観てしまい、涙腺対応でティッシュの山を築きながら作りました。

最初『春のゲージ祭り』というお題で記事を書こうと思っていろいろ準備していたら、いつの間にか体力ゲージができていました。マテリアルを使ったゲージで、なるべくパーツ数を抑えていろいろ表現できないかと模索しているところだったので、さっそく参考にさせてもらうことにしました。

マテリアルでいろいろやりすぎるとGPUの負荷が心配にはなりますが、ゲージなので面積は大きくはないし、表示するパーツ数を増やさず情報量を増やすことができるので、結果的にオートレイアウト的な処理が減ります。もちろん実機で負荷検証するのは必須なんだけど、よいこは真似してみてね。

 

マテリアルはこんな感じ

f:id:hiyokosabrey:20210416005711p:plain

予想値 現在値 をそれぞれ Step で 0 と 1 に分けたものに、0.8 と 0.2 をかけてます。

f:id:hiyokosabrey:20210416013016p:plain

f:id:hiyokosabrey:20210416012444p:plain

足し算して 1.0 になればOK。

これを Lerp ノード に渡すと、濃淡が表現できます。

f:id:hiyokosabrey:20210416211158p:plain

1.0 のところは、グラデーションがそのままで、 0.0 のところは ベースのカラーが、 0.2 のところは線形補間(Linear Interporate)された状態になります。

f:id:hiyokosabrey:20210416013441p:plain

これで、特訓によって減少するであろう未来が表現できた。

 

次は増加するときの見た目。

加算と減算で条件分岐、とかやりたくなかったので、

f:id:hiyokosabrey:20210416212421p:plain

予想値 と 現在値 の差分を 計算に利用します。

f:id:hiyokosabrey:20210416213413p:plain

これをゲージ本体のカラー(グラデーション)の底上げに使います。

f:id:hiyokosabrey:20210416214133p:plain

加算するといい感じになるように底上げ具合を調節。

f:id:hiyokosabrey:20210416214412p:plain

 

予想値が下回った場合は減算になります。

f:id:hiyokosabrey:20210416214813p:plain

マイナス値をどうにかしないと、ということで登場するのが clampノード。

clampノードは 指定した範囲をオーバーした値はカットします。

正確には、 Min を超えれば Min の値、 Max を超えれば Max の値になります。ノードのデフォルトが Min = 0、 Max = 1.0 なので何もつないでませんが、ゼロ以下の値が入ってくると、しれっと 0.0 を返します。

f:id:hiyokosabrey:20210416215447p:plain

回復分のカラーに 常にこのclamp後の値を掛けてるので、加算のとき、減算のときで、2種類の状態を作り出せます。

 

掛け算と足し算だけでもこういった条件分岐みたいなことができるので、面白いですね。

掛け算のこの3つパターンを押さえておくとイイことあるかもよ。

0 × 0 = 0

0 × 1 = 0

1 × 1 = 1

掛け算に ゼロ が入ると問答無用で ゼロになります。

また、イチ を掛けると何も変化しません。

この辺をうまく組み合わせて作っていきます。もし触るのをためらっているUIデザイナーがいらっしゃるなら、UI表現の幅も広がるので、恐れずにぜひいろいろ試してほしいです。

 

せっかくなんで増減するアニメーションを作ってみました。

f:id:hiyokosabrey:20210416221115g:plain

 

ブループリントでは、ゲージのImageにセットしたマテリアルを、Dynamic Materia lInstance として変数化しておきます。これを使ってマテリアルにアクセスします。

f:id:hiyokosabrey:20210416221620p:plain

予想値をもらって反映するイベント(または関数)も用意。

 

マテリアルのパラメータをセットする関数はこんな感じ。

f:id:hiyokosabrey:20210416221803p:plain

今回 Float型の変数は3つ使ってます。

f:id:hiyokosabrey:20210416222257p:plain

 

増減のアニメーションは Set Timer by Eventノードで。

f:id:hiyokosabrey:20210416222031p:plain

 

やりたい仕様がうまくできるとパズルが完成したような心持ちがします。

と思いつつも、ゲームをプレイしながら増減するときの動きをよくよく観察していると、重ねて処理しているように見えるので、今回のつくりは完コピにはならなかったけど、いろいろ検証できたので面白かった。

 

 

 

 

 

最近Twitterにあげたやつ その2

 

ふと思いついて試してみたシリーズ。

この 〇れ味ゲージは過去記事でやってまして、当時はマテリアルを使いました。

limesode.hatenablog.com結構ややこしいことしてましたね。

 

 今回は HorizontalBox を使います。マテリアルは一切使用しません。とてもシンプルです。

f:id:hiyokosabrey:20210416224826p:plain


HorizontalBoxをひとつ、子供として色のついた Image を入れます。

f:id:hiyokosabrey:20210416225020p:plain

HorizontalBoxの子になると、親のタイプに合わせて Slot が変化します。

f:id:hiyokosabrey:20210416225850p:plain

Size の値を変更すると、幅が変わります。

すべての Sizeを 1.0 にすると、すべてが等幅な状態になります。

ぴっちりと隙間なく自動で調整してくれるので、個別にSizeをいじってやれば棒グラフ完成です。

可変しなくて固定の棒グラフならこれを量産して、表示を切り替えるだけで使えそうです。でもやっぱりスクリプトから制御したいですよね。というわけで・・・

 

まずは、Size を適用する関数。

f:id:hiyokosabrey:20210416231416p:plain

Get Child At ノードは、 HorozontalBox の 子要素を、Index番号でアクセスできるようにするノードです。

下の Make系 ノードは単体で検索するより、この場合、右上の Set Size ノードの左のピン In Size からドラッグするとすぐ近くに見つかります。

f:id:hiyokosabrey:20210416231928p:plain

 

Float型の配列を一つ作って、適当な値(テスト用)を入れます。

配列の数は HorizontalBox の Image と同じ数。

f:id:hiyokosabrey:20210416232657p:plain

 

これを計算して比率を求め、上の関数で適用します。

いったん全部足して最大値を求め、それで割ることで一つ一つの割合がわかります。

f:id:hiyokosabrey:20210416232834p:plain

LastIndexの値は一応 引数として受け取れるようにしてます。
テストだったら固定値を入れたつくりでも問題ないですが、こうしておくことで、一度できたこの関数を編集する機会が減らせます。結果調整の手数が減ります。

 

グラフの表示を更新するイベント(または関数)

f:id:hiyokosabrey:20210416235045p:plain

ゲージ全体の長さは 0~1.0 で受け取る仕様。500は実際に表示する最大の長さ。

ゲージの長さを実際の表示幅で受け取る仕様だと、デザインやレイアウトの変更でゲージそのものの長さを変更する際に大きな問題となります。パラメータを管理する者と、デザインを管理する者はおそらく別々だろうと思うので、なおさらこういった配慮はメンテナンスのコストを下げる効果があります。

 

f:id:hiyokosabrey:20210417000108p:plain

できあがり。

 

グラデーションのテクスチャ作って Image にセットすると見た目を少しアレンジできます。

f:id:hiyokosabrey:20210417114830p:plain

f:id:hiyokosabrey:20210417114725p:plain

 

 

 

 

文字でも世界観を

遊んでいて最近気づいた。

f:id:hiyokosabrey:20210417011037p:plain

 基本的に『馬』の表記を「ウマ」「バ」と回避しつつも、「有馬記念」だけはどうしようもなかったんだろうな。『有マ記念』・・・『アリマ記念』

 で、結果フォントのグリフいじってるようですね。たった一文字、この一文字を加工するだけで、このフィクションな世界のリアリティを感じさせてくれる心遣いがステキすぎる。

 外字として追加するのが簡単だしコストが一番安くできるんだけど、置換が必要になるうえ、テキスト管理のコストや置換漏れの確認工数なんかがパないので、おそらく馬(U+99AC)のグリフそのものをいじる方が安全ということだろうと思われる。自分だったら確実にそう提案する。TextMeshPro(埋め込まずにAtlasを使用する方)使ってるんだったらマージしてるかもしれない・・・?

 フォントベンダーの名前が見つけられなかったんだけど、オリジナルフォントじゃなければそれなりにコストと期間は支払っているはずで、それでもやってやろうという開発スタッフの愛と意気込みに感服です。さすがに馬偏の漢字はいじってないみたい。

 

 

ではでは

今回はこの辺で

誰かの何かに役に立てれば幸いです

 

 

9スライスを試してみたメモ

ダイアログウィンドウなんかのサイズが可変するウィンドウでよく見かけるUI表示で、制作環境によって呼び名が変わるようです。9スライスとか、9-patch とかいうやつ。

UE4でももちろん標準実装されているのでとても手軽に使えます。

詳しくはこちらの記事。

historia.co.jp

普通に使えるのに、わざわざマテリアルで試そうと思ったのは、カラーを乗せたかったから。

で、できたのがこれ。

 

 

f:id:hiyokosabrey:20210404135055p:plain

AlphaチャンネルとRGBカラーを分離すれば実現できるはず。ということでマテリアルと格闘することになったのでした。

 

UE4の Mergin指定はデザインに対して柔軟に合わせられるつくりなので、真似してみたかったけど、まずはシンプルなところから理解していこうということにしました。

今回は作り方というより考え方の記録みたいな内容です。

 

下図は、UMGでの指定方法。

f:id:hiyokosabrey:20210404152543p:plain

考えやすいように、Marginは 0.5 固定で進めます。

Marginはテクスチャの分割位置を上下左右の端から割合で指定するので、全部 0.5 ということは中央になります。

 

用意したテクスチャ ↓

f:id:hiyokosabrey:20210404144830p:plain

 

実際に描画する際は、この4分割のパーツを9か所に配置することになります。

f:id:hiyokosabrey:20210404152307p:plain

縦と横の中央部が延ばされます。

 

マテリアルでこのようなUVを作れればOKなわけです。

f:id:hiyokosabrey:20210404153913p:plain

 

まずは U方向(水平)について考えてみます。

 

変化量を縦軸にしてグラフにすると下図のようなイメージになります。

f:id:hiyokosabrey:20210404160306p:plain

何も手を加えなければ、0 ~ 1.0 へのまっすぐな直線です。これを指定したSize固定部分で分断して引き延ばす感じ。

 

ノードで組んでみるとこうなりました。

f:id:hiyokosabrey:20210404161037p:plain

Scalarパラメータノードが Size固定部分の値になります。

そこを if ノードで判定して、ナナメ(0→0.5 と 0.5→1.0 )にするか、0.5 にするかを仕分けています。

もっと頭のいい計算方法があると思う。

パッと見ややこしいし、U方向だけでこのボリューム感。ついでにSize固定幅の指定をピクセルで指定したいので、TexCoord[3] を活用。

これについてはこちらのツイートが参考になりました。

 

コピペとはいえ V方向のぶんも必要なので最終的にこうなりました。

f:id:hiyokosabrey:20210404162522p:plain

 

コンパクトにしたいので、HLSLのコードを書ける Customノードを試してみました。

f:id:hiyokosabrey:20210404164709p:plain


 1 |  float temp = 0.5 / Width;
 2 |  float result;
 3 |  if ( Value < Width ){
 4 |    result = temp * Value;
 5 |  }else {
 6 |    if ( (1 - Width) < Value ) {
 7 |      result = (Value -(1 - Width)) * temp + 0.5;
 8 |    }else {
 9 |      result = 0.5;
10|    }
11|  }
12|  return result;

 

すっきり。

f:id:hiyokosabrey:20210404174746p:plain

 

今回 ノードで組むより、コードで書いたほうが Instructions(命令)数は少なくなった。

f:id:hiyokosabrey:20210404175137p:plain

 

使ったテクスチャはこれ。

f:id:hiyokosabrey:20210404200330p:plain

 

できたマテリアルは、いつも通り Image に貼り付けて完成。

f:id:hiyokosabrey:20210404193556g:plain

 

これで途中で伸びることなくカラーテクスチャが自由にオーバーレイできるようになった。

f:id:hiyokosabrey:20210404195354p:plain

UVの計算方法については、結果オーライでまったく自信ないので、どなたか頭のいい人ご指摘いただけるとありがたいです。

 

テクスチャの品質で圧縮による劣化を少しでもマシにしたくて、RGB と Alphaを別々の解像度で作って合体させるというのを実践しているのですが、今回のネタもそこからのつながりです。

まだまだ、応用できそうですが今回はこのへんで

 

 

ではでは

すてきな9スライス ライフを!

 

 

 

レーダーチャート作ってみた

 

f:id:hiyokosabrey:20210327154555j:plain

いやぁレーダーチャートですよ。ゲームのUI作ってると、避けて通るのが難しいというか、ヘタに避けると事故るというか、かといって簡単には実装させてくれないというツンなところが憎いレーダーチャート。ステータス画面でキャラの成長度合いや武装なんかの性能差をパラメータ表示する際に使われることが多い印象。

ポリゴンメッシュのような柔軟な形状変化は、半透明テクスチャベースでの2D表現ではほぼ無理(直線の組み合わせなので頑張ればできますが、なり力技で無駄なパーツも増える)だし、プログラマさんへの負担がかなり高いのもレーダーチャートです。なのでプログラマさんの顔色伺いながらデザイン提案してきました。

かねてからレーダーチャートを自力で作ってみたくて、思いついたアイデアを実践してみたのが今回つぶやいたやつです。

たまたま思ってた感じに動作してくれたので、メモしておきます。

三角関数とかベクトルとかそういった計算は一切使ってません。

主に掛け算と引き算です。

さすがに こんな変則的な作り方が採用されることはないと思いますが、参考になれば幸いです。

 

 

blenderでメッシュを用意する

Verは 2.92 です。大したことしないので旧いVerでも他のDCCツールでも問題ないです。まず円錐を作ります。6角錐でも5角錐でもOK。底面は不要。

スケール をゼロにしてぺちゃんこにつぶしたら、スケールを「適用」して 1.0 に戻す。

[ObjectMode] モード Object → Apply → Scale

f:id:hiyokosabrey:20210327155834p:plain

この時 底面が残っていると、ポリゴンが重なってしまって作業しづらくなる。

(ぼくはこの後 X軸を 90度回して Apply します。)

 

[Vertex Paint] モードにして 頂点カラーをつける。

f:id:hiyokosabrey:20210327161029p:plain

このとき 中途半端な値にならないようにしっかり塗る

色の順番は法則とかないので適当でも大丈夫。

ただし中央は動かないので 黒(0,0,0)または白(1,1,1)推奨。

 

色がついたら、FBXで書き出し。

(今回 FBXのバージョンとかはデフォルト設定のまま)

正面方向と上方向の軸に注意。インポートしてみて向きがおかしかったらモデルを回転させるか、FBXの書き出しで対応するかどちらかで。この辺は、作業のやりやすさと、エンジンにインポート後の配置のしやすさを考慮すると自然と決まってくる。はず。

 

UE4でのインポート時のダイアログで、

Vertex Color Import Option を  Replace に変更する。

f:id:hiyokosabrey:20210328004351p:plain

マテリアルの設定は

探さない、作らない、読み込ませない の3無い運動で。

f:id:hiyokosabrey:20210327163013p:plain

 

無事インポートできら材料は揃ったので、次はマテリアルをどうにかすればほぼ完成。

 

新しくマテリアルを作成したら、

ShadingModel は Unlit(光源計算なし)を選択。

まず VertexColor をつなぎます。

f:id:hiyokosabrey:20210328005311p:plain

 

プレビュー用のメッシュを登録すると作業がはかどります。

f:id:hiyokosabrey:20210328005030p:plain

 

 

できあがった全体図

f:id:hiyokosabrey:20210327165548p:plain

 

まずは頂点カラーを取り出すところ

f:id:hiyokosabrey:20210327165717p:plain

各頂点のカラーから、ある数字を取り出すのにカスタムノードを使用。

中身こんな状態。

f:id:hiyokosabrey:20210327170021p:plain

Codeのところは

return float((Red * 4) + (Green * 2) + Blue);

Red, Green, Blue は下の Inputsのところで設定した名前。

 

何をやっているかというと、

RGB を 111 の 2進数と見立てて 0~7 の 10進数 に換算してる。

f:id:hiyokosabrey:20210327171446p:plain

 

これで、各頂点に番号を振ったのも同然。

あとは、個々でパラメータを反映してやるだけ。

 

blender のVertexPaint は デフォルトだとアルファが使えないので、今回のやり方だとRGBの3つしか使えないけど、アドオンでアルファを使えるようにしたら、ARGBの 4つが使えるので、最大15個の頂点を制御できると思う。試してないけど。

 

あとは、この 1 ~ 6 の値を if ノードで判定しながら頂点を動かします。

f:id:hiyokosabrey:20210327221544p:plain

LocalPositionノードは、メッシュが持つ頂点の位置で、メッシュの中央からの座標になります。

上の図の場合、VertexColor が RGB(0,1,1) のとき(= 3) という値が来たときだけ、 ScalarParameter(上図のRightUpper)を流して、それ以外は 0 を流します。

マテリアルが受け取る値は 0 ~ 1

f:id:hiyokosabrey:20210327223033p:plain

0 のときMAXなんで、 気持ち悪ければ OneMinus ノード使ってもいいのですが、計算が増えるので処理負荷を考えてここは受け入れています。

各頂点は、Meshの原点から離れた位置にいます。ここに掛け算することで、方向を保ったまま、原点に近づいたり離れたりするわけです。

で、この掛け算した結果を、元の頂点位置から引き算することで結果的に凹みます。

用意したMesh が最大値の状態なので、こういった発想に至りました。

 

あとは連鎖的に、次々各頂点の計算をして引いていきます。

f:id:hiyokosabrey:20210327224400p:plain

もう少し違うやり方もありそうな気がします。

  

中央以外の頂点を計算し終えたら仕上げ。

f:id:hiyokosabrey:20210327224649p:plain

TransformPosition に渡して、そこから AbsoluteWorldPosition を 引いてようやく 出力できます。すでに存在するメッシュに対して、部分的に頂点を動かしたら、この計算しておくことで、相対的な動きになります。

Lerp ノードのところは、頂点カラーを確認するためのものなので、以下の形で問題ないです。

f:id:hiyokosabrey:20210327230809p:plain

マテリアルは完成です。

 

新しく Actorブループリントを用意して、StaticMesh を  AddComponent します。

そこに インポートしたメッシュと出来立てのマテリアルをセット。

 

f:id:hiyokosabrey:20210327231943j:plain

 

メッシュのマテリアルをいじるには、Dynamic Material Instanceを用意します。

 

f:id:hiyokosabrey:20210327232814p:plain


Targetにつながった StaticMesh は、 Viewportで追加したやつ。左のリストからドラッグ&ドロップ。

Source Material のところに 今回用意したマテリアルをセット。あとはReturnValue ピンから 変数に昇格(Promote to Variable)させておきます。

 

パラメータを管理するための配列を用意します。

f:id:hiyokosabrey:20210327233722p:plain

 

配列の中身を個別に取り出す関数

f:id:hiyokosabrey:20210327233833p:plain

Pure型にするのをオススメ

 

そして、この配列の中身を一気にマテリアルに反映するのがカスタムイベント。

f:id:hiyokosabrey:20210327234239p:plain

下のほう見切れてるけど、同じような形なので省略。

マテリアルパラメータ名と、配列変数の Index が合ってさえいれば問題なし。

 

ひとまずこれで必要なものは全て揃いました。

 

あとは配列の中身を書き換えて、カスタムイベントを呼ぶ。

これだけです。

 

Twitterにあげた動画は、ランダムにパラメータ書き換えて遷移するように特別に組みました。

エンジンの操作(オペレーション)についてはかなり省いているので、わかりにくかったらごめんなさい。謎なところなどあればコメントいただけると補間します。

 

正7角形までだけど、 頂点の数が変わっても簡単に対応できます。

使用できるカラーは以下の8色。

f:id:hiyokosabrey:20210328001003p:plain

RGBの各輝度は 1.0 = 255 です。実は blender のRGBの扱い方が 0~1.0 なのです。

f:id:hiyokosabrey:20210328001334p:plain

将来的に、HDR時代が当たり前になったら、255 とか FF みたいなこと言うと年寄り扱いされるかもしれないので今から慣れておくといいかも。

 

円錐の角数を変えてたので試してみた。マテリアルは使いまわし。

f:id:hiyokosabrey:20210328011746j:plain

ブループリント複製して、StaticMeshの中身差し替えて、減った頂点のぶん不要な処理を削っただけです。

 

ひとまずここまで作れて満足してます。

UE4は普通にメッシュ描けるので、ぶっちゃけこの方法は必要ないと思います。

頂点カラーで特定の頂点を動かすことができるのに気づけたのはよかった。

 

Widgetでシェイプが扱えるようになるといいな。

 

ではでは

すてきなレーダーチャートライフを!

 

UMGのスライダーをシークバー風に変える

先日のツイートを一応メモっておきます。

スライダー道は奥が深いですね。

 

きっかけは @HirofumiSeo さんのこのツイート

 

気になったのでいろいろ試してみるもドラッグ&ドロップでつまづいたので、取り急ぎ現行のスライダーを改造することにした次第。

f:id:hiyokosabrey:20210221103337p:plain

 

ちなみに ちゃんとドラッグできるやつはこちらの @seiko_dev さんのツイート。

 素晴らしいです。

 

今までゲームパッドありきで考える習慣のおかげで、ドラッグ周りの仕様を触ってこなかったのが悔やまれます。

でぼくが作ったのはこれ。

 

 

とりあえず作り方メモ

 

以前にも似たようなのを作ってましたが、ゲームコンフィグのような汎用性はいったん置きにして、1画面に1本想定、後からレイアウト調整がしやすいのを目指しました。

 

マテリアルパラメータコレクションを使います。

f:id:hiyokosabrey:20210221005001p:plain

f:id:hiyokosabrey:20210221005823p:plain

Scalarパラメータを追加。

 

このパラメータを使ってマテリアルを用意します。

f:id:hiyokosabrey:20210221011129p:plain

CollectionParameterノードに、用意しておいたパラメータコレクションをセットします。黄色いのがゲージカラー、グレーが下地のカラーです。

 

1パラメータ1マテリアルになるので、画面に同時に表示するスライダの数ぶんマテリアルアセットを用意する必要が出てきます。同時に表示しないのであれば使いまわせます。

 

次にWidgetブループリント

まずキャンバスを用意

スライダーたちを格納する HorizontalBoxから

f:id:hiyokosabrey:20210221105017p:plain

HorizontalBox に入れるUMGのパーツは3つ。

順番として ButtonSizeBoxButton になるように入れます。

それぞれに子供として、

TextBlockSlider を入れてます。

f:id:hiyokosabrey:20210221012919p:plain

プロパティを触るのは最小限にしたいので、なるべくデフォルト設定でレイアウトします。

 

HorizontalBox は中身に合わせて自動的にサイズを合わせる Size to Contents を有効にしておきます。

f:id:hiyokosabrey:20210221015200p:plain

 

  

 

スライダーの長さを調整する際の肝になるのが SizeBox

f:id:hiyokosabrey:20210221013650p:plain

Width Override で決定します。

 

UMGでは、HorizontalBox の子として、直接 Slider を入れると Slider の持つ Canvas Panel Slot が置き換わってしまう仕様になってます。おかげでサイズがちゃんと認識されなくなってしまうのを解決するためにSizeBoxでくるむことにしました。

 

↓左が通常時、右がHorizontalBoxの子にしたときの状態。

f:id:hiyokosabrey:20210221110440p:plain

このへんオートレイアウト系のしくみなので、おそらく何か理由はあると思いますが、スライダーのサイズ情報が別の Slot にあればよさそうではあります。

f:id:hiyokosabrey:20210221110515p:plain

 

 

スライダーの長さは SizeBox に任せるとして、見た目を整えていきます。

 

スライダーのパーツはシンプルな構成で2つ。

f:id:hiyokosabrey:20210221112606p:plain

 

Detail(詳細) パネルの Style の項目に Normal Bar ImageHovered Bar Image があります。

f:id:hiyokosabrey:20210221015456p:plain

Image のところに、用意しておいたマテリアルをセットします。

Normal は通常時、Hovered は マウスカーソルが上に乗った時を意味します。Normalの方の Tintカラーを少し暗くすると、操作したときに効果がわかります。

Disabled はスライダーが無効な時の状態ですが、条件的にあり得る場合はここにも同じようにマテリアルをセットしておきます。

Bar(溝) の下に 続けて、Thumb(つまみ)の設定と、Barの太さの設定。

f:id:hiyokosabrey:20210221112722p:plain

つまみのビジュアルはここで消します。

Draw As を None にすることで描画はされなくなりますが、Image Sizeは生きていて、Barの見た目の長さに影響するので、ゼロ にします。

f:id:hiyokosabrey:20210221113418p:plain

スライダーの長さにこだわるのは、スライダーで扱う最大値とピクセル表示量の差をできるだけ整数倍にしやすくするのが目的です。計算の仕組み上仕方がないと分かっていても、見た目に「わかる」「わからない」は重要です。にんげんだもの

というわけで、エンジンのお気遣いは排除します。これで単純に SizeBox の値だけでコントロールできるようになりました。

 

スライダーの設定はこれで終了。

次は 再ヘッダ的なカレント位置を示す TextBlock

 

f:id:hiyokosabrey:20210221104637p:plain
中央揃えf:id:hiyokosabrey:20210221012359p:plain にします。

数字と|は間に改行を入れて2行にしています。

行間は Line Height Percentage で調整できます。

f:id:hiyokosabrey:20210221121600p:plain

ブループリントから書き換えるので、 Is Variable を有効にするのも忘れずに。

f:id:hiyokosabrey:20210221121812p:plain

このTextBlockは ゲージの左端に合わせて座標を決めます。実際に動かす際は、RenderTransloation を使って相対的に動かすので、この初期位置だけを合わしておけばOK。

 

これでキャンバスの準備はできました。

次にWidgetブループリント

Float型の変数を作って、Event Pre Construct につないでセットします。

セットする値は、 SizeBox から取得します。

f:id:hiyokosabrey:20210221122729p:plain

もう一つ スライダーの最大量を保持する Float型の変数を追加。

f:id:hiyokosabrey:20210221125908p:plain

ついでにスライダーのプロパティもここで変更します。

 

スライダーの変更を見た目に反映する関数を作ります。

Bar部分にセットしたマテリアルを更新。

f:id:hiyokosabrey:20210221130809p:plain

テキストの内容とポジションを更新。

f:id:hiyokosabrey:20210221130818p:plain


ほぼこれで完成です。

試しに Event Construction に関数をつないで確認してみます。

f:id:hiyokosabrey:20210221135828p:plain

 

レベルブループリントからViewportに追加して再生します。

f:id:hiyokosabrey:20210221132854g:plain



あとはボタンを押したときの処理。

UI的には Numeric Stepper に相当します。

編集画面を Designer に切り替えて、Button のDetailタブ(詳細)からイベントを作成します。On Clicked のプラスボタンをクリック。

f:id:hiyokosabrey:20210221134525p:plain

イベントグラフにイベントノードが現れます。

f:id:hiyokosabrey:20210221135111p:plain

ここにクリックした際のふるまい(挙動)を用意します。

f:id:hiyokosabrey:20210221135359p:plain

 

再生して確認します。

ついでにボタンのテキストも変えてみました。

f:id:hiyokosabrey:20210221140051g:plain

 

改造は以上です。

 

実は UIデザイナー向けのポートフォリオUE4で作ろうというプロジェクトを目論んでいるので、ちょうどよいものができました。

スライドの切り替え等に使えそうです。

 

 

ここからはスライダーに関しての考察とかなんとか

スライダーといえば、ゲームコンテンツの話に限ると、遊びやすさをカスタマイズするためのセッティング画面で見かけるものがほとんどで、その用途はたいてい音量を調整するためのもの。他の要素もスライダーの形式をとりつつも、ステップ(刻み)がサウンドほど細かくないので、スライダーである必要がなかったりします。

 

用途と操作するデバイスによって有利不利があるので、全て書ききるのは文字量がえらいことになりそう、というか今はちゃんと整理できてないので、またどこかでまとめてみたいと思います。

 

UE4 の UMGに用意されているスライダーは、音声ボリュームの調整を主用途として想定されている印象。

クリックした際に、ポイントした位置につまみが移動するのは、今の位置から微調整したいわけではないのでは?と推測します。音量って、ステップ(変化の刻み)が細かくてちょっと動かしたぐらいでは、差異がわかりにくいのもあるのかなと思います。

よく見かける3つのボリューム SE、BGM、VOICE  のバランスをミキサーのように扱うからこそのスライダーだと考えると、精度というよりは比較を優先しているのかなと。

 

また、スライダーUIにとって、つまみの大きさと見た目は大変重要です。

マウスのような手首や腕で操作するデバイスでUIを細かく操作するのは、なかなか鍛錬が必要ですし、ゲームパッドに至ってはスライダーはフリーカーソルと並んで操作が面倒なUIの上位にくるやつです。それぞれでつまみに対する最適なサイズがあります。

 

今回の事案で、いくつか設定されている機能要件の中に、

つまみをマウスボタンで押下しただけでは動かない

つまみ以外でクリックしたらその場所につまみがジャンプする

の2つがあります。

 

仮に一つ目の要件を満たしていたとしても、

つまみのサイズ小さくしすぎるとカーソルを合わせにくくなり、ジャンプしやすくなるので要件を満たすのは難しくなります。

大きすぎると、そのぶん離れた位置にしかジャンプできなくなります。

なかなか興味深い悩みです。

 

つまみの大きさについては、マウスを操作する方のシチュエーションとスキルによって決めていくことになると思います。

センサーの分解能や、カーソルスピードも関係します。ボタンを押下したときにマウスが動いてしまうとかも対策が必要かもしれません。

 モニタの大きさと解像度の関係も大事です。

 

こういった用途や使う人に合わせて細かいチューニングが必要なのが、UI開発の面倒くさいとこでもあり、また面白いとこです。

常に最適解を求めていくのが大事という志向なので、基本、「使いまわし」 は考えないようにしています。使いまわすのはパーツやアセットではなく経験則。

実際に試してみると、気づかなかったいろんな事象がチラチラするので、試行錯誤はやってやりすぎるということはないなと思っています。

 

にしてもUE4のドラッグ周りの仕様が少し見えてきたので、もっと検証してみたい。マルチプラットフォーム開発は、特定のデバイスに例外的に対応するのは避ける傾向があります。最大公約数というかベン図の重なったところで答えを見つけようとするので、どうしてもそのデバイスの性能をどこかで切り捨てているのも事実。パズルのようで難しいですがうまく解決できるように、いろんなアプローチを試していきたいですね。

 

なんか長くなりましたが今回はこの辺で

 ではでは

ステキなスライダーライフを!

 

 

 

 

 

雑記#20210219

最近Twitterにあげたやつ

f:id:hiyokosabrey:20210215231418g:plain

 

とくに何かに使えそうというほどのものではないけど、つい出来心で「テクスチャ1枚できそう」って思ってしまったやつ。

f:id:hiyokosabrey:20210215235610p:plain

 ゲームって、基本リアルタイムレンダリングです。AfterEffectsのように、どんなに重い描画処理だろうと1フレームずつキッチリ計算してエンコード、後から滑らか再生といういうわけにはいかないので、効率のいいデータ管理や描画処理が求められます。その中でも UIに関しては、メモリに常駐させる要素も多く、扱えるデータや処理は他のキャラや背景、エフェクトに比べると圧倒的にシビアです。

 テクスチャを複数枚持つのと、1枚にまとめるのとでは、占有するメモリサイズが同じでも効率が変わってきます。テクスチャキャッシュの使い方とファイルアクセスの回数をできるだけ少なくする工夫がポイントだったりします。テクスチャが大きすぎても逆にキャッシュに乗らなくて効率が下がることがあります。 この辺は新しいハードが出るたびにちょっとずつ技術革新がなされているので、徐々に頭を悩ませる機会は減ってる気はしますが、ゲームの構造が複雑になってるぶん別の悩みに置き換わっている気がしないでもないです。

 

長々と書いてしまいましたけど、参考程度に作り方のご紹介。

まずは回したい素材をモノクロのフラットな絵で用意します。

テクスチャサイズは 128x128

f:id:hiyokosabrey:20210216001531p:plainf:id:hiyokosabrey:20210216001759p:plain

以前にもブログに登場した MendakoChanです。

これをPhotoshopでアルファチャンネルにします。

次はRGB(色)チャンネルのレイヤーを作ります。

f:id:hiyokosabrey:20210216002011p:plain

レイヤーのブレンドは、 覆い焼き(リニア)-加算 にします。

この状態でテクスチャに描き出してみます。

 

UE4にインポートしたら、マテリアルはこのようにつなぎます。

f:id:hiyokosabrey:20210216003507p:plain

これで、リング3つ分作ったら Widgetで重ねて表示してみます。

f:id:hiyokosabrey:20210216003644p:plain

隙間が空いてしまいました。

そこで、テクスチャにリングに一工夫。

 

ほんの少し小さい黒丸を間に 通常ブレンドで挟みます。

f:id:hiyokosabrey:20210216004149p:plain

 

f:id:hiyokosabrey:20210216004925p:plain

黒丸を入れることで、テクスチャにリングができたので、マテリアルは Subtract が減った分シンプルになります。

f:id:hiyokosabrey:20210216005237p:plain

f:id:hiyokosabrey:20210216005248p:plain

f:id:hiyokosabrey:20210216005258p:plain

確認してみます。

f:id:hiyokosabrey:20210216005557p:plain

隙間が消えました。いい感じです。

あとは、時間差をつけてアニメーションさせるだけ。

f:id:hiyokosabrey:20210216005857p:plain

 

f:id:hiyokosabrey:20210216010737g:plain

キャプチャが若干同期してなくてぎこちないですがなんとか完成です。

 ちょっとやってみたかっただけのネタです。

何かのヒラメキになればいいのですけど・・・

 

 

マダミス遊んだ

先日、マーダーミステリーというジャンルの『狂気山脈 陰謀の分水嶺』 というゲームを遊びました。この記事では内容には触れないのでご安心を。マダミスはここ数年での人気がうなぎ上り?のようで、気にはなりつつも、ある程度人数が揃わないとプレイできないというのと、昨今の感染症対策により指を咥えて眺めるしかなかったのでした。

ふと雑談のはずみで、急遽やろうということになったので、バタバタと準備を進めることに。

いろいろ訳あって、ボイスチャットの環境を用意してなかったので、やんわり断ろうと思ったけど、このまま時代の にノリ遅れるのはカッチョ悪いよなと思い、家族の前ではいつかリモートワークをする日がくるかもしれないなどとつぶやきながらなんとか書斎を確保。

Discord の扱いも含め完全なる初心者だったので、最初は緊張したけどそのうち慣れた。音声の調整に手間取ったので、なんかうまいことフィードバックできる仕組みがあればいいなと思う。

 

で、ボイスチャットは Discord 、 ゲームはオンラインセッションツールとして ココフォリア を選択。

プレイは共有のボードに並んだカードをめくりつつ、会話しつつで進めていく。カードは最初「非公開」の状態で伏せられてて、めくる際には「全員に公開」と「自分だけが見る」という状態を選べる。これだけの操作で、十分ゲームになりうるのがすごい。全体公開はそのまま隠し事はしません、というポーズになるし、特定の誰かを揺さぶる効果もある。自分だけが見る場合、カードの情報をそのまま伝えてもいいし、嘘を混ぜてもいい。見せないことで疑惑の種を蒔くこともできる。

そもそものゲームのメカニクスがうまくできてるのもあるけど、アプリ的にインターフェイスを見てみるととてもシンプル。カードのグラフィックの上で右クリックして選択するだけの機能があれば遊べてしまう。あとはカードやチップ、トークンなどのグラフィックを配置して、マウスでドラッグできれば十分だ。テキストチャットとダイスロールの機能も用意されてるので、結構な数のアナログゲームが遊べそう。ネックになるとしたらハンドアウトなど諸々のグラフィックを用意する手間かな。裏と表の扱いも準備するとなれば大変そう。

とはいえ物理カードがなくても遊べるのが素晴らしいので、オリジナルのアナログゲームを作ってみたいなと思ったら、印刷しなくても、この環境で遠くの仲間とテストプレイしたり調整できるのはすごくいい環境。

 

とまぁ、

そんなこんなで、とても楽しく遊べました。シナリオも面白かった。

額を寄せ合って遊ぶアナログゲームにとっては厳しいご時世ですが、こういったセッションツールやチャットの環境がどんどん登場して進化してるのは興味深いですね。

アナログゲームデジタルゲームの境界が一部で溶けていく感じがして、ちょっとワクワクしてます。

 

 

ではでは

今回はこの辺で

 

 

 

 

 

 

ゲージの見た目をいじる

前回の続きです

ゲージの見た目を改造していきます

f:id:hiyokosabrey:20210209005614g:plain

 

まずはテクスチャを使ったアレンジ

といってもグラデーションを乗せるだけ

 

用意したのは 128x16px のテクスチャ。

f:id:hiyokosabrey:20210209010121p:plain ← 実寸

 

インポート時にタイリングの設定を変更しておきます。

f:id:hiyokosabrey:20210210000359p:plain

UVを動かしたときに、狙った状態にするためです。

 

前回のマテリアルで、囲みの部分を消します。

f:id:hiyokosabrey:20210209011728p:plain

f:id:hiyokosabrey:20210209012014p:plain

空いたとこに テクスチャを

f:id:hiyokosabrey:20210209012513p:plain

VTilingの値を小さくして、ScalarParameterの値で上下に移動することで、見た目をチェンジ。

f:id:hiyokosabrey:20210209012638p:plain

 

テクスチャを使ったアレンジは以上です。

 

 

つぎはテクスチャではなくカーブアトラスを使ってみます。

 

 

 まずはコンテンツブラウザで右クリック > ミソレニアス > カーブ

f:id:hiyokosabrey:20210210000330p:plain

カーブタイプを訊かれるので、CurveLinearColor を選択。

f:id:hiyokosabrey:20210210000650p:plain

f:id:hiyokosabrey:20210210000637p:plain

 これを編集してグラデーションを作ります。

f:id:hiyokosabrey:20210210000807p:plain

アニメーションカーブみたいなグラフなので戸惑いますが、慣れれば面白くなります。

 

同じように、チャージ中のグラデーションも用意します。

f:id:hiyokosabrey:20210210001235p:plain

カーブアセットを2つ作ったら、次はカーブアトラス。

コンテンツブラウザで右クリック > みそれにあす > カーブアトラス

f:id:hiyokosabrey:20210210001406p:plain

f:id:hiyokosabrey:20210210001425p:plain

開くと、ウィンドウ右側のペインで、カーブをセットすることができます。

f:id:hiyokosabrey:20210210002011p:plain

Texture Size は 大きいとメモリがもったいないので、カーブの細やかさに合わせて加減します。今回は 128 にしました。 64 とかでもよかったかも。

 

これでグラデの準備は完了。

マテリアルに組み込んでいきます。

前回のマテリアルから、囲みの部分を消します。

f:id:hiyokosabrey:20210210002502p:plain

 ノードを消すと、 if ノードにエラーが点灯しますが慌てない。

f:id:hiyokosabrey:20210210003014p:plain

ここに CurveAtlasRowParameter ノードを2つ取り出します。

f:id:hiyokosabrey:20210210003203p:plain

それぞれに適当な名前を付けてつなぎます。

f:id:hiyokosabrey:20210210003631p:plain

CurveTime ピンには、 TexCood と UV の Uを取り出す ComponentMask(R)をつなぐことで、水平方向のグラデーションテクスチャとして扱えます。

 

カーブパラメータノードの中身はこんな具合。

f:id:hiyokosabrey:20210210003619p:plain

 アトラス と カーブ をペアにしてセットします。

 

これで完成。

テストしてみます。

 

f:id:hiyokosabrey:20210210004935g:plain

 

カーブアトラスについてはヒストリアさんのブログで取り上げられています。

[UE4]カーブアトラス(Curve Atlas)アセットを使ってみる

https://historia.co.jp/archives/10594/

 

 

最後におまけ

 

上下方向にタイリングするテクスチャを用意。

f:id:hiyokosabrey:20210210012104p:plain 256x32

容量節約のため グレースケールでインポートします。

これを前回のマテリアルに追加します。

f:id:hiyokosabrey:20210210012911p:plain



どうなるかというと・・・

f:id:hiyokosabrey:20210210012632g:plain

回復中であることを強調できました。

 


マテリアルしかいじってないので、プログラマと分業しているなら、前回の Widgetブループリントはプログラマに預けてしまって、見た目のポリッシュに専念できると思います。

 

開発プロジェクトの規模が大きくなると、まずは最低限の仕様を満たしたアセットをサクッと作ってコミット。そして組み込んでもらって使えるかどうかの検証をしてもらっている間に、様子を見つつブラッシュアップ。というのが僕がよくやるスタイル。

データを差し替えるだけで見た目がアップするのはステキじゃないですか?

しかもアセット編集がぶつからないのが理想的!

 

 

おまけのオマケ

タイリングテクスチャを作っているときに偶然発見した錯視

f:id:hiyokosabrey:20210210014406p:plain

青い枠線のタテの線が平行じゃないように見える。

 

 

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

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

 

 

 

 

 

自動回復するゲージ

なんとなく両端から増減するゲージを作ってみたくなって、マテリアルで試してみた。

 

ゲージは見た目を気にしないのであれば、スケールを可変する方法がサクッと作れるのでいいと思う。ただスケール方式の場合、下敷きが必要だし、成長要素で最大の長さが伸びていく場合に扱いがちょっぴり面倒だし、ゲージにテクスチャを貼るとスケールによって伸び縮みしてしまったりして、つくりがシンプルなぶん、表現の自由度は少し下がると思っています。

 

f:id:hiyokosabrey:20210203002145p:plain

 

というわけで今回は マテリアルを使って作ります。

 

最近何かといじらせてもらってる step ノードさんに登場していただきました。

f:id:hiyokosabrey:20210205010821p:plain

まずはシンプルにカラーだけでの構成。

 ScalarParameterで受け取った値を計算して、ゲージの塗分ける場所を求めています。

f:id:hiyokosabrey:20210206114815p:plain

 水平方向のゲージなので、Texcoordノードの U の値を ComponentMask(R) で取り出して step で 0 と 1 の状態にしています。

f:id:hiyokosabrey:20210206120631p:plain

両サイドからの位置を 2つの step で求めて、引き算しています。

f:id:hiyokosabrey:20210206120526p:plain

もっと賢い方法がありそうですが、ぼくの脳ミソではここまで。

 

見た目のアレンジは後程紹介するとして、自動回復するブループリントを作っていきます。

 

UMGのキャンバスに Image を一つおいて、マテリアルをセットします。

f:id:hiyokosabrey:20210206122129p:plain

ついでに登場演出も作っておくことにします。

f:id:hiyokosabrey:20210206222557g:plain

Render Transform の Scale X を 0 から 1.0 にするだけの簡単なアニメーション。

 

キャンバスはこの辺で。

 

ここからはWidgetブループリント。

 

作った登場演出のアニメーションを再生するカスタムイベントを用意。

f:id:hiyokosabrey:20210207102507p:plain

アニメーション終了の検出が必要であれば、イベントディスパッチャーなんかを追加したりしますが、今回はゆるめの仕様でいきます。

 

Float型の変数と、ゲージ使用不可フラグのBoolean型の変数、ゲージの見た目を更新する関数を用意します。

f:id:hiyokosabrey:20210206214557p:plain

Float型はそのままゲージの量で%で管理したいので、0.0 ~ 1.0 で扱います。

Boolean型はフラグとして扱います。スタミナゲージ的な仕様にしたくてゲージが完全にゼロになるまでは消費できるけど、いったん空になると、満タンまでチャージしないと消費できないチャージ状態に、というやつです。

 

表示開始時に満タンから始まる想定なので、Event Pre Construct で初期化してます。

ブループリントの変数は初期値を持たせることができるのですが、グラフ上に set ノードの状態で置いておくと確認がしやすいのと、スクショで説明しやすいので、個人的にこのつなぎ方はよく使います。Viewportへの付け外しが起こる場合は気を付ける必要がありますけど。

 

 

関数の中はこんな状態。

f:id:hiyokosabrey:20210206124830p:plain

マテリアルのパラメータに値を渡すだけ。

 

Widgetに任せない実装で、プログラマとアーティストが分業体制なのであれば、ここまでをUIアーティストが作ってコミットすれば最低限の機能だけで 「あとよろ」できます。

せっかくなんで、プロトタイピング的に作ってしまおうと思います。

 

次は

満タンになるまで少しづつ増加するカスタムイベント。

f:id:hiyokosabrey:20210206214904p:plain

満タンじゃない状態のときは 右端の Set Timer by Event ノードで自身のイベントを呼ぶ仕様。小数点というのもあって、確実にキレイに 1.0 にならないことを考慮して、少しでもオーバーしたら、強制的に 1.0 にしてタイマーストップ。

 

次は

ゲージを減らすためのカスタムイベント。ちょっと大きいので画像を分割。

前半↓

f:id:hiyokosabrey:20210206215328p:plain

後半↓

f:id:hiyokosabrey:20210206215342p:plain

 

この Set Timer by Event が呼び出すイベントは、先に作っておいた 回復イベントです。

赤いラインを引っ張ってつないでもいいのですが、見た目にちょっとあれなんで、Create Event ノードを使います。これは遠く離れたイベントにつなぐことができます。

f:id:hiyokosabrey:20210206182748g:plain

ノードの Select Function... と書かれたプルダウンリストから、つなぎたいイベントを選択します。ここは先に作っておいた ゲージ回復イベントを指定。

これで、Time に設定した 1.0秒後に回復を開始します。

 

だいたい完成。

 

レベルブループリントで確認していきます。

f:id:hiyokosabrey:20210207103949p:plain

Create Widget ノードに、今回のWidgetをセット。

Return Value ピンからドラッグすると、作ったカスタムイベントが取り出せます。

出現のイベントと、ゲージを減らすイベントを取り出して、適当なキー&ボタン操作をつないだら準備完了。

 

f:id:hiyokosabrey:20210207105613g:plain

 

さてさて

空になった時のチャージ中はゲージ消費できない仕様であることをプレイヤーに教えないといけません。いまのままでは見た目に区別がつかないので細工を入れていきます。

 

まずはマテリアルに点滅表現と、カラーを切り替える仕組みを追加します。

f:id:hiyokosabrey:20210207111703p:plain

Scalar Parameterif ノードを使って、通常時 と 回復時 の2つの状態を切り替えるつくりです。

これを、つなげます。

f:id:hiyokosabrey:20210207112101p:plain

マテリアルは、ひとまずこれで。

次は Scalar Parameter を変更する仕組み。

Widgetブループリントに新しく関数を追加。

f:id:hiyokosabrey:20210207113025p:plain


マテリアル内の if ノードで比較するので、その判定に合うように数値を渡します。

f:id:hiyokosabrey:20210207112925p:plain

できた関数を、イベントグラフのカスタムイベントにつなぎます。

つなぐ場所は2か所。

ゲージ回復イベントで満タンになったときの最後と。

f:id:hiyokosabrey:20210207113631p:plain

ゲージを減らすイベントの空になったときの最後。

f:id:hiyokosabrey:20210207113640p:plain

 

これで確認してみます。

f:id:hiyokosabrey:20210207114020g:plain

想定した仕様になりました。

 

 

長くなったので、今回はこの辺にしておきます。

次回は見た目のアレンジをやってみようと思います。

 

ではでは

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