みつまめ杏仁

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

クリックした場所にメニューを 2

前回の続きです。

マウス座標を取得して、そこにWidgetを表示することができました。次はアイコンを並べていきます。

f:id:hiyokosabrey:20181212235226g:plain

 

 アイコンのテクスチャとマテリアル

↓このようなアイコンのテクスチャを用意。サイズは256x256で、1つが 64x64なので16個分持つことができます。

f:id:hiyokosabrey:20181213214603p:plain

これをマテリアルを使って切り出せるようにします。

f:id:hiyokosabrey:20181213215229p:plain

アイコンの並びは、開発途中で、入れ替わったり使わなくなることがよくあるので、Index番号で管理できると便利です。その番号をマテリアルが受け取って計算するようにしています。Fmodは 剰余(割った余り)Divide は割り算、Floor は小数以下切り捨てをするノードです。

 

マテリアルができたら、ブループリントの編集です。

 

Widgetブループリント

Event Pre Construction で変数の初期化をしています。

新しく、Integer型が1つ、Float型が2つ、Text型が1つ、計4つの変数を用意。

f:id:hiyokosabrey:20181213223323p:plain

「定数」は、一度定義したら最初から最後まで値の変わらない値です。メニューアイテムの数が決まっている前提で、アイコン同士の間隔(角度)と、マウス判定用の範囲(角度)をここで事前に計算させています。「角度」と「ラジアン」混在してたりするので頭悪い感じですが、その辺はいったん棚に上げておいていただけると助かりまする。

 

 前回の記事で書いていませんが、今回のリングメニューはいつでも呼び出せるので、Viewportに常駐させる想定で作っています。出現と退出は Visible ←→ Collapse を使っているので、この初期化処理は1回だけ走ることになります。コンテキストメニューのように動的にアイテム数が変わるようにするのであれば、関数化すれば対応できます。

 

次に、Event Construct でアイコンを並べます。

ちょっと大きいので画像を分割して、前半部分から。

f:id:hiyokosabrey:20181213231048p:plain

 For Loop でループさせます。 ループ回数の指定が Last Index なので、アイテムの個数から -1 しないといけないのが面倒です・・・。First Index を1にするという手もあるのですが、Index番号を 計算に使用するので、 0 始まりの方が都合がいいのです。

 

 画像の右端にあるのは、Create Dynamic Material Instance ノードで、指定したマテリアル アセットから、マテリアルインスタンスダイナミックを生成します。WIdgetブループリントでよく使う Get Dynamic Material ノードとは、引数にマテリアルのついたUMGのImageパーツを渡して使うところが異なっています。今回は、Imageパーツをキャンバスに置かずにブループリントから生成しているので、このようなマテリアルの扱い方になっています。

 

後半部分。

f:id:hiyokosabrey:20181213233023p:plain

今回 アイコンの番号は素直にForLoop の Index を使っていますが、別途配列を用意すればアイコンの並びを管理できます。例えば下図のような感じになります。

f:id:hiyokosabrey:20181213234046p:plain

 

マクロの中身はこんな感じ。三角関数のサインとコサインが登場します。

f:id:hiyokosabrey:20181213235350p:plain

Sinθ と Cosθ の θに角度(ラジアン)を入れてXとYの値にすると円周上のポイントになります。Sin、Cos はそのままだと  -1 ~ 1 の値を返すので、半径を掛けて円を大きくしています。

いろいろ補正しているので、ややこしい感じですが、補正を無しだと ↓ こうなります。スッキリ。

f:id:hiyokosabrey:20181214000506p:plain

 

これをキャンバスで確認すると、

f:id:hiyokosabrey:20181214000641p:plain

キャンバスの左上が (0, 0)原点なので当然ズレます。

リングの大きさを 320 としているので、その半分のサイズがズレ幅になります。ここも最初に定数化しておく方がいいと思います。右下に +160 足せばポジションは収まりそうです。メニューの開始位置を上にしたいので、90度 = π/2 = π*0.5 を足しています。

 最後に、好みですが、逆時計回りにするために、Y座標を求める Sin にマイナスの半径を掛けています。

f:id:hiyokosabrey:20181214002038p:plain

 

 

ここで一旦確認してみます。

f:id:hiyokosabrey:20181213234832g:plain

よしよし。

 

 

最後の仕上げ

マウスの座用からハイライトさせる

EventTick で処理します。常時という訳にはいかないので、フラグでコントロール

リングメニューが出ている間だけ動くようにして、結果を新しく用意した変数に取り置き。

f:id:hiyokosabrey:20181214004250p:plain

 

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

f:id:hiyokosabrey:20181214005328p:plain

最初にマウスのボタンを押した場所をVector2D型の変数に保存しているので、今の場所から引き算することで差分が出ます。つまり出現場所からどれだけマウスが動いたかが分かります。その場所から、 atan2 という演算ノードを使うことで、角度を求めることができるのです。

f:id:hiyokosabrey:20181214234029p:plain

 戻り値(ReturnValue)は Radians(θ)とDegrees(°)の2タイプあります。

ラジアンだとうまく説明できる気がしないので、Degreesの方を選択しています。

 

基本的な扱い方なら、 A と B の軸と角度の関係は↓のようになります。

f:id:hiyokosabrey:20181214233050p:plain

 

Viewportの座標空間は左上が原点で、見えているのはプラスの領域になります。なのでここで差分をとると↓のようになります。

f:id:hiyokosabrey:20181215075153p:plain

Y軸の符号が逆になります。(現在位置からスタート位置を引いているのでX軸は問題なし)

今回リングのてっぺんをIndexの0にしたりしてるので、いろいろ試してみた結果、アレンジして atan2 ノードに渡すことにしました。アレンジの内容はY軸の符号を逆にして、A=Y / B=X のところを、 A=X / B=Y に変えています。出てきた角度は下図のようになってます。

 

f:id:hiyokosabrey:20181214233141p:plain

角度をIndex番号にする際に、マイナスの値は使いづらいので、+180します。

f:id:hiyokosabrey:20181215000650p:plain

これを、最初に定数化しておいた値で計算していくのですが、簡単な例で図にしていきます。

 

 まずメニューアイコンが 8個の場合だと、45という数値が得られます。

 

360° ÷ 8個 = 45°  

f:id:hiyokosabrey:20181215081637p:plain

この範囲にマウスカーソルの角度がある場合、そのアイコンを選択していることにすればいいのです。なのでカーソルのいる場所を角度にして、45で割って小数点以下切り捨てれば、メニューのIndexにマッチした数が得られそうです。

 

でも、上の図だとアイコンのまん中に区切り線がきています。

本当は下図のようにしたいのです。

f:id:hiyokosabrey:20181215082501p:plain

さぁ、困ったぞ。判定用に角度を調節するか、と考えたけど、これ以上角度をいじるのは灰色の頭脳がとろけるチーズになりそうだったので、そこは諦めることにして、最終的に「もう半分にしたらどうか?」という発想にたどり着きました。

 

45を得てから2で割るのもノードが増えて処理がもったいないので、360ではなく180を割ることにします。

180° ÷ 8個 = 22.5°

 

半分なるとどうなるかというと、

f:id:hiyokosabrey:20181215084301p:plain

この考え方で、角度を 22.5で割って、小数点以下切り捨てると下図のようになります。

f:id:hiyokosabrey:20181215085625p:plain

例えば、 atan2 が 30°という値を返してきたら、30 ÷ 22.5=1.3333・・・

なので、小数以下切り捨てると 1 という数字になります。

 

ここまでの説明はマクロの中身では下の明るくなっている部分にあたります。

f:id:hiyokosabrey:20181215090416p:plain

 

まだ 0~15 なので、これをどうにかして 0~7 にしないといけません。これがマクロの右上の部分。

f:id:hiyokosabrey:20181215090736p:plain

0~15 を半分にして、小数点以下を切り上げ、それをアイテムの個数で割った余りが答えになります。

まず半分(BPでは 0.5を掛けてます)にして・・・

f:id:hiyokosabrey:20181215091150p:plain

小数点以下切り上げます。Ceil(シール)を使います。

f:id:hiyokosabrey:20181215091352p:plain

だいぶいい感じです。

あとは一番上の 8 が 0 になってくれれば完璧。

8はアイテムの個数と同じ、ここは 剰余先生の出番です。

f:id:hiyokosabrey:20181215091935p:plain

ようやく、角度がいい感じにIndex値になりました。

 

この値をフォーカスの判定に使います。イベントグラフに戻って続き。

左端にマクロがあります。

f:id:hiyokosabrey:20181215092721p:plain

マクロで得た値は一旦変数に保存します。

 

ForLoopで何度も判定するので、マクロから戻り値を直接つなげてしまうと、何度も無駄にマクロの計算が走ってしまいます。

f:id:hiyokosabrey:20181215093306p:plain

ForLoopで0から順番にチェックしていって、同じ値のものだけハイライト処理をします。

 

ではさっそく確認。

f:id:hiyokosabrey:20181215094125g:plain

 

5個のとき。

f:id:hiyokosabrey:20181215094410g:plain

 

16個!

f:id:hiyokosabrey:20181215094716g:plain

 

なんとか完成です。

アイコンにマウスイベントをセットすると、四角形でしか判定できないし、アイコンの無い部分の判定が難しくなります。また重なると優先の問題が発生します。

ちょっと計算が多くて大変そうに見えますが、角度で判定すればマウスイベントは不要にできます。さらに外側にサブメニューなんかのリングを出す場合は、中心からの距離を判定に加えればよさそうです。なんかリングメニューが攻略できた気になってきた。

 

もっと頭のいい方法があると思うけど、いったんこれで満足しておこう。

ふぅ。

 

いつものことだけど、作ってからいろいろ思いついたりするので、次回もう少しだけ続きを書こうと思います。

 

ラジオからはクリスマスソングが流れてます。

ではでは

ステキな リングメニューライフを!

 

 

 

 

クリックした場所にメニューを

 ゲームパッド操作のUIは今までたくさん作ってきた。最初からマウス操作で設計することはなく、まずゲームパッド用のUIで問題なく遊べるとこまで作りきる。そして後から少ない工数と期間で必要最小限の箇所にマウスのアタリを追加する。

 そんな申し訳程度の対応ではさすがに最近は心が痛むので、UE4で一人もくもく会を開いているところです。

 今回作ってみたのはリングメニュー。見た目に「パイメニュー感」が弱いのでリングメニューと呼んでます。パイメニューは最近だとRDR2で実装されてるのが確認できます。アナログスティックと相性がよかったり、タッチなどポインティング操作にも対応可能な便利なやつです。今回作った仕様としては、

  • 画面の適当な場所でマウスの右ボタン押下で表示開始
  • ボタンを離すと選択終了
  • メニューの数を変更可能(※アイコンの密度と処理が許せば何個でも)
  • キャンセルはない(※メニューのどれかを「閉じる」にして対応可)

といった内容。

f:id:hiyokosabrey:20181209205852g:plain

 マウスのアタリ(ヒットエリアと言った方がいいのかな)を長方形(UMGのパーツ形状に依存)でしか取れなさそうで、いろいろ試してみた結果、今の自分のスキルではUMGを使って作れるのは上のようなものが精いっぱいでした。

 

 てなわけで、試行した結果を書いておきます。参考になれば幸いです。

 

 

マウスイベント

まずはマウスでポイントした位置情報が必要です。

適当なWidgetブループリントを一つ新しく作って、カスタムイベントを用意します。

f:id:hiyokosabrey:20181209213631p:plain

↑とりあえず値を確認するためのものです。

 

マウスのポジションにはいろんな取得方法が用意されているようです。

ひとつはマウスイベントから取得する方法。

f:id:hiyokosabrey:20181209223721p:plain

マウスボタンを押下したときのイベント、On Mouse Button Downという関数をオーバーライドすると、MouseEventというパラメータピンを利用できます。そこからPointerEventカテゴリのノード2種、Get Screen Space PositionGet Last Screen Space Position を使うとスクリーン上のマウスポジションを取得できます。使い分けについてはまたいずれ検証してみたいです。上図のような利用だと、両者は同じ値を返します。

ちなみにこの方法は、キャンバスに何かしら配置している部分のみでしか検出しないので、今回のリングメニューUIには向いてないようです。

 

 

つぎは、通常の関数で取得する方法。

On Mouse系のイベントと違って、好きなタイミングで場所を選ばずに検出できます。

キーワード get mouse でサーチすると3つほどヒット。

f:id:hiyokosabrey:20181209213314p:plain

 この3つのノードをカスタムイベントにつないだら、

テストのためにレベルブループリントからInputイベントで呼び出して確認してみます。

f:id:hiyokosabrey:20181212204456p:plain

 

 

まずは上から Get Mouse Position on Platformの場合

f:id:hiyokosabrey:20181209225329p:plain

これは、Viewportではなく物理的な画面内でのマウスのポジションを返してきます。画面解像度より小さいウィンドウ表示だとおかしな値に見えます。

↓下図は解像度1920x1080のモニタを使っている場合。

f:id:hiyokosabrey:20181210212017p:plain

 

Get Mouse Position on Viewport の方は、

f:id:hiyokosabrey:20181209231330p:plain

ウィンドウの大きさに関係なく、設定されているWidgetの解像度でマウスポジションを返してきます。デフォルトだと1920x1080。

f:id:hiyokosabrey:20181210214028p:plain

 

3つ目の Get Mouse Position Scaled by DPI も 上図同様に Viewportの左上が(0,0)で、右下が設定した解像度になるようです。

Pure型でPlayerをつないでやる必要があるので、つなぎ方は↓このようになります。

f:id:hiyokosabrey:20181210221619p:plain

2番目の ~ on Viewport と、この ~ DPI でウィンドウサイズをぐりぐりしながら値を比較してみたところ、同じ値が返ってきたので、とりあえず使いやすそうな2番目の Get Mouse Position on Viewport で作ることに決めました。

公式のドキュメントにも "Use GetMousePositionOnViewport() instead."  (代わりに~を使いなさい)と書いてあるのでそうすることにします。

 

リングを作る

クリック位置が分かるようになったので、その場所に表示するWidgetを用意します。

リングはテクスチャを使わずにマテリアルで用意します。

f:id:hiyokosabrey:20181212212130p:plain

VectorToRadialValueノード は距離と角度によった値を提供してくれます。 

円系の画像は無駄が多いので容量の節約になるのと、ピクセルという制約が無いのでリングの太さやシャープさなんかが後からいくらでも調節できるので便利です。最終的に見た目が確定してしまえばグレースケールのテクスチャと差し替えてみて負荷の小さい方を取ればOKでしょう。

一応4つある Const ノードの説明を図にしておきます。

VectorToRadialValueの Linear Distanceピンは最初↓のような値が出ています。

f:id:hiyokosabrey:20181212213858p:plain

白い四角は表示されたときのサイズとします。どんなサイズでもこの値は変わりません。外側の薄い青色は値の範囲を分かりやすくするために塗っています。

この値を、SmoothStepを使って、大小2つの円を作ります。

f:id:hiyokosabrey:20181212222044p:plain

Minの値は、限りなくMaxに近い値で、ボケずにジャギらない程度になるよう加減します。

SmoothStepの Min と Max は Photoshopのグラデーションをイメージする分かりやすいと思います。近いとシャープになって、離れるとボケます。

f:id:hiyokosabrey:20181212222625p:plain

で、大きい方の円を OneMinus で反転してから、2つの円を掛け算すれば完成。

f:id:hiyokosabrey:20181212223145p:plain

白は1、黒は0です。

掛け算の基本。

1×0=0 または 0×0=0 または 0×1=0

1×1=1

です。

f:id:hiyokosabrey:20181212223841p:plain

Final Color を白にしておくと、UMGで自由なカラーが付けられます。

これを、UMGでImageに張り付けます。

 

UMG

まずは一つにまとめるためのキャンバスパネルを用意します。

f:id:hiyokosabrey:20181212224507p:plain

Anchorは中央。ここに サイズ 320x320 の Image と TextBlock をひとつづつ入れます。Image にはリングのマテリアルをセットします。

リングの中央がキャンバスのPivotになるように、Alignmentの値を調整します。

f:id:hiyokosabrey:20181212224750p:plain

あとは適当に、出現と退出のアニメーションを作ります。

 

 

アニメーションの再生と停止

アニメーションができたら、ブループリントの編集です。

まず変数を2つ用意します。

f:id:hiyokosabrey:20181212225750p:plain

重複再生(連打)防止と、クリックした位置を覚えておくためのものです。

isActive は 初期値を False にしておきます。

 

次に

アニメーションの再生中に別のアニメーションを再生するときに強制的に停止するマクロを用意します。

f:id:hiyokosabrey:20181212230128p:plain

引数(Inputピン)を WidgetAnimation にしておくことで、汎用的に使えます。

再生中に限り強制的に停止させます。再生中でなかったら何もせず抜けます。

 

でこれらを使って、出現と退出のカスタムイベントを2つ用意します。

まずは出現イベント。

f:id:hiyokosabrey:20181212230751p:plain

 すでに出現していれば無視するようにBranchノードで判定します。

まだ出現していなければすぐにフラグを立てます。

クリックした位置を変数に入れて、その位置にキャンバスを持って行って出現アニメーションを再生する流れです。

 

つぎに退出イベント。

 こちらはシンプル。f:id:hiyokosabrey:20181212231241p:plain

 

あまりモタつかせたくないので、アニメーション再生中でも強引に、出現と退出ができるようにしています。出現で完全に開ききる前に退出の動きになると、アニメーションの見た目に不都合が出る場合は、BPで対策を入れるか、尺を短めにすることをお勧めします。

 

この辺でひとまずテストします。

レベルブループリントで Widgetの描画と、入力の処理を行います。

まずViewportに表示して、さらにマウスカーソルの表示を有効にします。

f:id:hiyokosabrey:20181212232601p:plain

Set Input Mode Game And UI ノードは マウスの有効範囲とかドラッグ操作をどうするか設定できるノードです。

 基本 Do Not Lock ですが、ドラッグ中にカメラが動いてほしくないので、 Pressed の判定中は、 Lock on Capture にしています。f:id:hiyokosabrey:20181212233304p:plain

これで試してみると・・・

f:id:hiyokosabrey:20181212235226g:plain

 無事うまくいってるようです。

 

 次回は、円状にアイコンを並べて、マウスの角度をみてハイライトする処理について書きます。

 

ではでは

すてきなマウスポジションライフを!

 

 

あとがき

 大体動作する状態になったので、そろそろ記事を書こうとしていたらお気に入りのUSBファンが動かなくなった。PCの冷却ファンにファンガードと直接ゴム足がねじ止めされてるやつで、置き方を選ばないのが嬉しい。見たらケーブルが切れてた。ラップトップでUE4をいじってるとかなり発熱するので、USBファンを利用してるんだけど、この時期は扇風機を回すとさすがに寒い。唯一となった冷却装置が機能しなくなったのでUE4をいったん終了。もう一度結線したら直るかなと思ったけど、はんだゴテを持ってなかったのであきらめた。結局ヨドバシカメラで同じやつが売ってたので購入。構造が頼りないのでまた切れそうな気もするけど、間に合わせということにして、早めに代替機の情報を集めよう。

 

 

 

スライダーを作る《本編》

 続きです。

 トグルスイッチのUIパーツを作り始めて、今はスライダーを作っています。デザイナとプログラマが作業するアセットで被らないようにできればいいなと思って模索していましたが、さっそく諦めました。てへぺろ

 コンパクトにしたいというデザインを優先したのも理由の一つですが、スライダーの操作がクリック処理だけじゃダメなのもあって、やっぱりイベントディスパッチャーとバインドを使った方がいいということに至りました。むしろ積極的に使っていった方がいいUIが作れそうだと感じました。このあたりの振る舞いって、作ってみないと気づけない事があるなぁ、と改めてUE4のありがたみを実感しています。

 

ということで今までの記事のリンク

前回の記事までで、一応分業体制は維持できていると思います。

f:id:hiyokosabrey:20181119001938p:plain

関数名や、パラメータ名などの多少の情報共有はありますが、アセットを双方が編集する機会はなくても大丈夫なはず。

 

・・・

 壁壁壁

今回スライダーUIを実装するにあたって、いくつかの壁にぶつかりました。

まず一つ目の壁が、このちっちゃいスライダーをどうやって扱いやすい大きさにするかでした。そこに出した答えがポップアップウィンドウです。設定ウィンドウ的なものが開いたら、まずはクリックするところから始まるのは変えられないので、トグルスイッチ同様クリックしたら何かしらの応答が必要。レイアウトを崩さずに操作可能であることをユーザーに伝えるには最適、という判断です。

 

 次にぶつかった壁があります。

 ユーザーが必ず変更の意思を持ってクリックするとは限らないので、うっかりの場合などはキャンセルできないと、ストレスになります。 

 ポップアップウィンドウを閉じるときに、「決定して閉じる」と「キャンセルして閉じる」という2拓の壁が立ちはだかったのです。「はだかる」って漢字表記があるのか気になったので調べたら「開かる」って書くみたいですね。すみません余談でした。

 ユーザー操作のフォーカスがポップアップウィンドウに移っている以上、メインだったwb_main は待機状態。ポップアップウィンドウが閉じられれば、何らかの結果を受け入れる必要があります。変更するのか、しないのか。その意思が判明した時点で処理が分岐することになります。この解決方法がイベントディスパッチャー。

 最初ポップアップウィンドウ以外をクリックしたら決定して閉じて、右クリックしたらキャンセルして閉じる。という仕様だったのですが、伝わらないし、ポップアップが出ているときに他の項目をクリックしたら閉じてすぐに開くのか、はたまた無視するのか、どちらがいいのか判断がつかない。ベタに決定とキャンセルのボタンを配置することにしました。

 

 そして最後の壁、それはドラッグ操作です。

 最初自前でやってやるぜ!って意気込んでみたものの、ちょっとブログに乗せるにはしんどいものが出来上がりました。これでは読むのもしんどいし、参考にするにもちょっと面倒な感じ。そこで既存のスライダーコンポーネントを使うことにしました。素直な使い方はしていませんけど。

 

 できたのがこれです。

f:id:hiyokosabrey:20181121011923p:plain

 

前回使用していたテクスチャにパーツを追加しました。

サイズはそのままで、OK、Cancel ボタンが加わって、ウィンドウの下敷きが縦長になってます。

f:id:hiyokosabrey:20181121014938p:plain  f:id:hiyokosabrey:20181121014950p:plain

(↑実データを原寸でPNGにしてるのでPhotoshopで再構成すれば使えると思います)

前回の方法で、マテリアルインスタンスを作って、パーツを切り出します。

 

 ポップアップウィンドウ用に新しくWidgetブループリントを用意します。

 キャンバスに、ポップアップウィンドウの大きさのキャンバスを置いて、中にImageを置きます。この Image の Anchor は 縦横にストレッチするやつにします。親キャンバスのサイズを変更すると追随するようにします。ポップアップウィンドウの下敷きになります。

前回の記事で用意したマテリアルからインスタンスを作成して、UVを切り出します。

f:id:hiyokosabrey:20181121231045p:plain

上から、Tiling U、V、Offset U、V の順です。

UV切り出しの計算が合っていれば↓このようなプレビューなります。無理やり正方形に引き延ばされます。

f:id:hiyokosabrey:20181121231427p:plain

この切り出したパーツを、キャンバスのImageパーツにセットします。

f:id:hiyokosabrey:20181121231501p:plain

 Draw As の設定を BOX にすると、ちゃんと9スライスのグリッドとして扱ってくれます。

f:id:hiyokosabrey:20181121231616p:plain

この上にパーツを置いていきます。

値を確認するための TextBlock、スライダーのバー、Min と Max を表すアイコン、まずはこれらを配置。中央揃えにするのでAnchorは

f:id:hiyokosabrey:20181122000546p:plain がオススメ。さらに それぞれのパーツの Pivot X を 0.5 にすると、左右対称に配置しやすくなるので超オススメします。 X座標が単にプラスかマイナスかになる。

f:id:hiyokosabrey:20181122000241p:plain

 Min と Max のアイコンは飾りです。これもマテリアルインスタンスでUVを切り出します。

f:id:hiyokosabrey:20181122001446p:plain

TextBlock は Is Variable にチェックを付けて中央に置きます。

 

スライダーのバーは、専用のマテリアルを用意。

f:id:hiyokosabrey:20181122001630p:plain

テクスチャを使わずに、2色のゲージです。Threshold (閾値)という名前の ScalarParameter を用意して、ブループリントからいじれるようにしています。

UMGのスライダーコンポーネントに適用が可能ですが、ブループリントからマテリアルにアクセスさせてくれないので、このような構造にしました。

f:id:hiyokosabrey:20181122002155p:plain

ここに、スライダーコンポーネントを重ねてるように配置します。

f:id:hiyokosabrey:20181122002346p:plain

置いてみるとものすごく小さいのでびっくりです。

f:id:hiyokosabrey:20181122002554p:plain

設定は Detailsタブから行います。とりあえず長さ(Slot > Size X)を先のImageパーツに合わせたら、StyleにあるBar Imageの描画(Draw As)を None にします。

f:id:hiyokosabrey:20181122003326p:plain

 

スライダーのハンドル(つまみ)のデザインもマテリアルインスタンスでUVを切り出せば差し替えることができます。Style の Thumb Image。

f:id:hiyokosabrey:20181122004332p:plain

f:id:hiyokosabrey:20181122004718p:plain

"Style" では "Thumb Image" だけど、 "Appearance" では "Slider Handle" って言ってるので、最初見たとき 「???」ってなった。

 

結局スライダーのバーを色分けしたかったので、UMGのスライダーコンポーネントをカスタマイズしました。いじったのは2か所。

・バーは、別のImageパーツで代替するために非表示にした。

・ハンドル(つまみ)をオリジナルのデザインに差し替えた。

 

 あとは、

決定ボタンとキャンセルボタンを追加すればUMGは終了です。

ちょっと楽するために、これもUMGのボタンコンポーネントを使います。

f:id:hiyokosabrey:20181123011950p:plain

2つ並べてマテリアルインスタンスで切り出したテクスチャをセットします。

f:id:hiyokosabrey:20181123014952p:plain

マウスイベントがあらかじめ用意されているので、それに合わせてセットします。

f:id:hiyokosabrey:20181123015116p:plain

通常で白、マウスオーバーで、うっすらカラーが入って、クリックで暗めのカラー、という設定です。

 

 

 UMGの各種コンポーネントには専用のイベントがいくつか用意されています。利用方法についてもいくつかあって、今回は2つのタイプを使います。

 

まず1つめ。

ボタンコンポーネントの詳細設定の一番下に、イベントを追加する部分があるので、

On Clicked イベントを追加します。

f:id:hiyokosabrey:20181123020335p:plain

クリックすると、自動的にGraph編集に切り替わります。赤いイベントノードが置かれているので、ここにイベントディスパッチャーを用意してつなぎます。

f:id:hiyokosabrey:20181123020601p:plain

イベントディスパッチャーは、エディタの左側、My Blueprintタブの一番下から作ります。

f:id:hiyokosabrey:20181123214355p:plain

クリックしたら、適当に名前をつけて、下のDetailsタブから、Inputsピンをひとつ追加します。

f:id:hiyokosabrey:20181123215602p:plain

 

 スライダーの値を管理するために、Float型の変数をひとつ作ります。

f:id:hiyokosabrey:20181123215925p:plain

この変数と、イベントディスパッチャーを、On Clickedイベントノードにつなぎます。

f:id:hiyokosabrey:20181124063909p:plain

 

f:id:hiyokosabrey:20181124064125p:plain

これで、ポップアップウィンドウから、決定 か キャンセル の通知を発行する仕組み(イベントディスパッチ)が用意できました。

 

 ポップアップウィンドを閉じたり開いたりという動作を、ポップアップウィンドウ側が行う場合は、ここに閉じるアニメーションをつなぎます。今回の記事では、説明が長くなりそうなので、ポップアップウィンドウを呼び出す側で表示の制御をします。

 

次にスライダーバーのマテリアルをいじるために、MID(ダイナミックマテリアル)を用意します。

f:id:hiyokosabrey:20181124070439p:plain

 

 イベント利用タイプ2つめ。

 スライダーにもボタン同様にUMGのコンポーネントとして、いろいろとイベントが用意されていますが、ここはイベントノードではなく、バインドの形で On Changed Value イベントを利用します。

f:id:hiyokosabrey:20181124071409p:plain

 

 上記2つのイベント処理は実際には処理の順番を基準に考えて使い分けるといいです。バインドの場合、イベントを受け付けるタイミングが制御できるのがウリで、入退場イベントがある場合に最適。バインドの解除には Unbind ノードを使います。

赤いイベントノードを使う方(緑色のボタンから作る)は、対象のパーツが表示されていれば、いつでもどこでもイベントの受付ができるのがウリですが、演出アニメーションの再生中など、操作してほしくないタイミングの場合があると注意が必要です。

 

 

一通りイベントが用意できたので、スライダーからの値を受け取って見た目に反映する関数を用意します。

f:id:hiyokosabrey:20181124080739p:plain

 setValue という名前の関数で作り始めたら、スライダー自身も同じ名前の関数を最初から持ってました。

 スライダーの値を受け取って、 最初の方に用意した Float型の変数に格納しておきます。Lerpノードに入っている値は、スライダーのハンドル(つまみ)を端っこに動かした際の、TextBlock の Render > Tlanslation 値です。ここで変数 Value が更新されます。スライダーが変更されるたびに 0.01.0 の値が入ってきます。

 

この関数を、スライダーの On Changed Value のバインドノードにつなぎますが、ちょっと手順が大事です。

f:id:hiyokosabrey:20181124082406p:plain

Custom Eventノードは、先に用意しておいてもいいですが、パラメータのピンが一致していないとつながらないので、上記の手順をオススメします。

 

以上でポップアップウィンドウ完成です。

f:id:hiyokosabrey:20181124084249p:plain

 

仕上げに、呼び出し側でポップアップウィンドウを呼び出して値を受け取れるようにします。

 

User Createdのカテゴリに作ったポップアップウィンドウが増えているのでキャンバスに配置します。

f:id:hiyokosabrey:20181124083842p:plain

最初からは表示しないので、Visivility は Collapse にしておきます。

 

Graphに移って、変数を2つ追加します。

f:id:hiyokosabrey:20181124094855p:plain

 Boolean型は、ポップアップウィンドウが出ている間、他のクリックを封印するためです。初期値は falseにしておきます。

 wb_sliderg型は、アクティブになっているスライダーを特定するための器です。

 

 変数が用意できたので、ポップアップウィンドウが出ているかどうかで処理を分けます。前回の On Mouse Button Down 関数の一番最初にブランチを挿入します。

f:id:hiyokosabrey:20181124111617p:plain

これでポップアップが出ている間、クリック判定を無視します。

スライダーがクリックされたら、の処理を追加します。

f:id:hiyokosabrey:20181124112703p:plain

 

ノードが増えてきたので、ポップアップを出す処理をマクロにします。

f:id:hiyokosabrey:20181124101509p:plain

startSlider という名前にしました。

これをつないで、↓のようになります。

f:id:hiyokosabrey:20181124112857p:plain

右端上のノードは ポップアップウィンドウの 閉じる通知を受け取るための Bind ノードです。ポップアップウィンドウを開いた直後にBindしておきます。開くと同時に閉じるための準備をしておくイメージ。

右端下の Create Event ノードは、通常のGraph内だと、Custom Event がつなげられるのですが、ここは関数内で Add Custom Event ができないためにの ノードです。

Select Function のままでコンパイルすると、エラーになりますが、まずは先に進めます。

 f:id:hiyokosabrey:20181124132747p:plain

 

この一式をスライダーの数ぶんつなぎます。↓全体図

f:id:hiyokosabrey:20181124113813p:plain

次に、BindしたCreate Event のためのイベントを用意します。

 

これはポップアップウィンドウから 値を受け取って反映したあと、閉じる処理になります。

カスタムイベントを用意して下図のようにつなぎます。

f:id:hiyokosabrey:20181124133430p:plain

イベントディスパッチャーから渡されてくるパラメーターは、Float型がひとつだけ。0以上の値なら、ユーザーが変更して決定ボタンを押した証拠。-1ならキャンセルボタンを押したことになります。値を反映するかしないかの分岐のあと、ポップアップウィンドウが閉じられるので、Bindを解除→非表示→ フラグを元に戻す という処理になります。

 

これを並べたスライダーの数ぶん(=CreateEventの数)用意します。

Unbindノード以降は共通なのでまとめると以下のようになりました。

f:id:hiyokosabrey:20181124133957p:plain

カスタムイベントが用意できたので、ようやく Create Event ノードのSelect Function を変更できます。プルダウンリストになってるので探します。

リストに表示されている内容は、プログラム的な表記になってます。

イベント名(パラメータ名)

f:id:hiyokosabrey:20181124135542p:plain

これでコンパイルするとエラーが出なくなります。

 

以上でポップアップウィンドウの実装完了です。

再生してみると、

f:id:hiyokosabrey:20181124190844g:plain

結構いい感じだと思うのですがいかがでしょうか?

 

 キャンセルという仕様を無くしてしまえれば、ポップアップウィンドウの外をクリックして反映→閉じる。という振る舞いをさせることもできます。設定をリセットするボタンを置くのもありですが、タッチ操作を考えると不用意に触ってしまうのを防ぐのは難しいので、キャンセルボタンの存在は意外に重要かも、と思ったりしてます。

 入力デバイスによって期待される振る舞いを、空気を読むように実装するのは難しいですね。

 

 作業分担的なチャレンジのつもりが、イベントの発生タイミングと、階層のあるUIを効率よく扱うには、イベントディスパッチャーを使うと便利ですよ、というサンプルになりました。

慣れてくればそれほどややこしいものでもないと思うので、

 変動するUIの主従と、その瞬間に誰(プレイヤーおよびUIパーツ)がどこで何をしたらどうなるのか?

を想像しながら少しづつ振る舞いを試していけば、ブループリントだけでプロトタイプ的なものは作れると思います。作ってみて触ってみてを繰り返して、例外の存在に気づけたり、予期しない動きが新しいUIのヒントになったり、とにかく経験あるのみです。もっともっと面白いUIが出てきてほしいので、UIデザインをされている方にはぜひアンリアルエンジンでUIを遊んでみてほしいです。

 

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

 

ではでは

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

 

 

あとがき1

UVの切り出しでは結構細かい小数が出てきます。割り切れるようなサイズでUVの範囲を調整しているので、256を掛けるとピクセル単位の値が出てきます。でもUE4の仕様で、表示桁数が多いと見た目に丸めて表示してくれることがあるので、このページに載せている画像の値を掛け算すると、小数のままになるものがあったりします。

 

 

あとがき2

この記事を書いている途中で、ぷちコンの参加賞が届きました。

よく見たらヒストリアスタッフさんによる「ぷち賞」を受賞していました!

ぱちぱちぱちぱち~

ステキな賞品ありがとうございます。大事に使わせてもらいます。

また次回頑張ろう。

 

 

 

 

 

 

 

次はスライダーを作る《準備》

以前にもスライダーを作って記事にしましたが、今回はマウス操作専用です。

前回のトグルスイッチと同じところに並べて使う想定のUIパーツなので、引き続き同じアセットもいじりつつアップデートしていこうと思います。

 

で、さっそく

テクスチャをひとまとめにしてしまおう

スライダーのパーツもひっくるめて一枚のテクスチャに収めることにします。

どうせ同じタイミングで読み込まれるんだったら、枚数が少ない方がいろいろ効率的です。

256x256のテクスチャにまとめました。左がRGB、右がアルファチャンネルです。

f:id:hiyokosabrey:20181115225148p:plain f:id:hiyokosabrey:20181115225138p:plain

まだ余裕がある状態ですが、追加要素のためにキープ、ということにしておきます。

テクスチャの切り出しが面倒なのが残念ではありますが、ゲームのロードが少しでも早く終わるなら、ユーザーの利益につながります。必要経費として頑張ります。

 

UVの範囲はレイヤーで管理しています。 

f:id:hiyokosabrey:20181117005108p:plain f:id:hiyokosabrey:20181117013615p:plain

 パーツごとに、適当なカラーで四角く塗り分けたレイヤーにパーツ名をしっかり付けて、レイヤーグループにまとめておきます。中のレイヤーは透明度100%でもレイヤーグループを半透明にすると上図のような状態にできます。

テクスチャとして書き出す際は、レイヤーグループをまるっと非表示にすればOK。

この方法だと、パーツの用途がはっきりするし、場所を入れ替えるときも重なりを回避できるし、アルファチャンネルの移動も確実に行えます。部分的に塗りつぶしたりするときもこの範囲レイヤーからの選択範囲が重宝するし、光彩なんかのボケ足の確認もしやすいので、私はいつもこの方法で管理しています。

 

さてさて

このテクスチャをUE4にインポートしたら、マテリアルを用意します。

f:id:hiyokosabrey:20181117010807p:plain

切り出しサイズを決める『Tiling』はMultiplyで、切り出す場所を決める『Offset』はAddノードで計算します。それぞれ U と V があるので、Scalar(スカラー)Parameter を4つつないだ方が、パラメーターの名前も付けられて分かりやすくなるのですが、Vector Parameterにすると、ブループリントから一気に4つの値が渡せるのでノードが少なくなります。

 

下のようにしても問題は無いです。

f:id:hiyokosabrey:20181117011902p:plain

 

マテリアルはこれで完成です。

 

 マテリアルインスタンスでパーツを切り出そう

次にこのマテリアルを親にして、インスタンスを作成します。

コンテンツブラウザのマテリアルアセットのアイコンの上で右クリックします。

f:id:hiyokosabrey:20181117012347p:plain

コンテキストメニューってやつですね。選択しているアイテムに合わせてメニュー内容が変わるという。ここからマテリアルインスタンスを作ります。

作ったらパラメータを編集します。

f:id:hiyokosabrey:20181117013106p:plain

値の計算方法は前回の記事で説明しているので省きます。

とにかくテクスチャサイズで割ると求められます。

f:id:hiyokosabrey:20181117015505p:plain

UMGで使用する パーツとして切り出したい数ぶんマテリアルインスタンスを用意していきます。

細かいパーツごとのパラメータは、次回の記事で書いていくとして、前の記事のトグルスイッチのマテリアルが修正になります。

セットされているテクスチャを今回のやつに変更したら、

f:id:hiyokosabrey:20181117104359p:plain

場所と横幅はそのままでテクスチャの高さだけが変更になったので、TexCoord ノードのパラメータを変更するだけです。

f:id:hiyokosabrey:20181117103914p:plain

 

トグルスイッチのマテリアルが変更できたら、

スライダー用のマテリアルを作ろう

いよいよスライダーのマテリアル。作り方はテクスチャアセットアイコンの上で右クリックです。Create Material して、マテリアルドメインを UserInterfaceに変更するとこまでは、目を瞑っててもできるくらいじゃないといけませんね。

私はできませんけどね。

で、内容はこんな感じ。

f:id:hiyokosabrey:20181117105001p:plain

テクスチャを部分的に切り出すので、TexCoordノードのパラメータは、

f:id:hiyokosabrey:20181117105149p:plain

場所が少しずれてるので Add ノードを入れて、OffsetV に 0.25 を固定値としてつないでいます。各パラメータをテクスチャに重ねるとこんなかんじ。

f:id:hiyokosabrey:20181117111143p:plain

スライダーは、ハンドル(つまみ)が左右に移動します。

それをトグルスイッチの時と同様にUVを動かして再現します。

テクスチャ的には、細かい小数点で管理された、完全にデザイナー都合のUV配置なので、ここで大活躍するのが Lerp ノードです。

Lerpノードの、ピンAとB にスライダー両端のOffsetU。AlphaピンをScalarParameterにして、ブループリントから値を受け取れるようにしています。

 

正式名称は Linear Interpolate といって線形補間してくれる便利なやつです。ちょっとわかりにくいかもしれないですが、 UV移動で スライダーの 0 から 満タン まで移動する場合の値の変化を図にしてみました。

f:id:hiyokosabrey:20181117133622p:plainf:id:hiyokosabrey:20181117134129p:plain

プログラマ的には、テクスチャ内のレイアウトに依存したUVアニメーションの調整なんてマッピラゴメンだと思います。Lerp ノードを使うことで、その辺の責任をしっかり取れるUIデザイナーになれるという訳です。

スライダーで扱う値はたいてい 0~100% のような『割合』が多いので、そのまま 0~1で制御できた方が分かりやすいし扱いやすいです。プログラマからは、0~1で値を受け取って、マテリアルの中で、いい感じに補正してやるのです。あとからテクスチャ内のレイアウトを変更しても、変更するのはマテリアルアセットのみです。UIデザイナーだけで完結できます。

 

スライダーのマテリアルができたので、Widgetを作っていきます。

 

スライダーのWidgetをつくろう

 まずはTextBlockと共にキャンバスに配置します。

f:id:hiyokosabrey:20181117211619p:plain

 スライダーの部分はトグルスイッチ同様に、マテリアルをセットします。

TextBlockはラベルと数値の2つ。それぞれ Is Variable にチェックを付けておきます。

 

キャンバスはこれで完成。

Graphに移動してさっそくGet Dynamic Material ノードで、スライダーとしてセットしたImageパーツから、Material Instance Dynamic を作ってお変数化しておきます。

f:id:hiyokosabrey:20181117225007p:plain

まずはスライダーのハンドルと値を変更するための関数。

f:id:hiyokosabrey:20181117212425p:plain

 Float型の値を、直接Text型にキャストするノードが ToTextノードです。小数部分はいらないので設定を少しいじります。▽をクリックするとこのノードの設定が変更できます。

f:id:hiyokosabrey:20181117223559p:plain

Rounding Mode の Half to Even は、端数を丸める処理をいくつかある中の一つです。

端数は小数部分で、 0.5 以下は切り捨てで 0 、0.51 以上は切り上げて 1 にしてくれます。

 

次に、スライダの初期設定をする関数を用意します。

f:id:hiyokosabrey:20181117224232p:plain

 テキストラベルを書き換えて、先に作っておいた、値を更新する関数を取り出してつなぎます。

 

これでWidgetは完成です。

前回のトグルスイッチと同じところに並べます。

f:id:hiyokosabrey:20181118014110p:plain

ストラクチャにも専用のパラメータを追加します。

f:id:hiyokosabrey:20181118014637p:plain

 

ストラクチャの更新ができたら、スライダーにも初期値をセットしてやります。

f:id:hiyokosabrey:20181118015330p:plain

ノードの位置を変えていますが、前回作った wb_main のイベントです。

 

今回はここまでにします。

表示を確認してみます。問題なければ値が反映されているはず。

f:id:hiyokosabrey:20181118015957j:plain

 

レイアウトと見た目の都合で、ミニスライダーになってしまいました。

とうわけで

クリックする部分は次回《解決編》で。

 

ではでは

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

 

ストラクチャの書き換えについて

トグルスイッチをいじってて気づいたメモ。

前回の記事でストラクチャの内容を、一部だけ書き換える際に以下のようにしていたんだけど、

f:id:hiyokosabrey:20181107235718p:plain

部分だけを更新するノードがありました。

下図のこの部分を、

f:id:hiyokosabrey:20181114203308p:plain

Set Member in xxxx ノードに置き換えます。

ストラクチャ型の変数ノード(GET)から探すと見つかります。

f:id:hiyokosabrey:20181114203530p:plain

f:id:hiyokosabrey:20181114203735p:plain

このままだと値を渡せないので、Set Member ~ノードをフォーカスした状態で、Detailsタブを確認。

チェックボックスが並んでるので変更したい値のチェックボックスをONにします。

f:id:hiyokosabrey:20181114204214p:plain

f:id:hiyokosabrey:20181114204459p:plain

ノードに入力ピンが追加されるので、ここに接続すればOK。

 

Breakノード側は行き場をなくした出力ピンが寂しい状態なのですが、これを隠すことができます。

Breakノードをフォーカスした状態で、Detailsタブを見ると、Hide Unconnected Pins というボタンがあるのでクリック。

f:id:hiyokosabrey:20181114204924p:plain

これでかなりすっきりします。

f:id:hiyokosabrey:20181114205139p:plain

 

パラメータが増えるたびに、面倒な感じになるなと思ってたけど、ちゃんと用意されてました。てへぺろ

 

 

腰を痛めてしまい安静にするしかない状況で、長く座ってると辛いのですが、いくぶん楽になってきたので、記事更新。

スライダーを作っているので、近日公開します。

 

ではでは

すてきなストラクチャライフを!

イテテ

 

 

 

スライドするトグルスイッチを作る

 久しぶりの更新です。まだそんなに秋を堪能してないのに年賀状が売られていたり、おせちの予約受付とか始まってて、年末感が漂ってくるのが切ない・・・梨食べたくなってきた。

 さてさて、ネタを探す旅に出てました~てへぺろ、とか言えたらまだ良かったんだけど、実際は毎日帰るのが遅く、仕事で睡魔と戦うのに精一杯で記事を書くエナジーが無かったのです~てへぺろ

 今回は、トグルスイッチを作ります。ゲームのオプション設定とかでよくあるUIで、ON か OFF かの2つの状態を切り替えるスイッチです。チェックボックスも同じ機能を持っているんだけど、アニメーションさせた方がリッチに見えるので、スライドするタイプをマテリアルで表現します。値の管理方法として他の設定項目のことも考えてストラクチャを使ったりしています。また、イベントディスパッチャーやバインドは使いません。最後の方にUI制作のワークフローについて少しだけ触れています。

 

f:id:hiyokosabrey:20181104234530j:plain

クリックするたびに切り替わります。

f:id:hiyokosabrey:20181104235057g:plain

UV移動なので、スライドをやめればいつでもチェックボックスに転用できます。

 

まずテクスチャを用意します。

f:id:hiyokosabrey:20181110130710p:plain

 

Sizeは 256x64 で RGBはこんな感じ。

f:id:hiyokosabrey:20181105232325p:plain

フリンジが気になる場合は黒い部分をなくしてカラーを入れます。

アルファチャンネルは片側だけを白くして抜きます。

f:id:hiyokosabrey:20181105232353p:plain

 

これをマテリアルで制御します。

f:id:hiyokosabrey:20181110130810p:plain

 

f:id:hiyokosabrey:20181105233938p:plain

テクスチャの一部分を切り出すには、TexCoord ノードのタイリングを利用します。

縦方向(V)は全部使うので 1.0 のまま。横方向(U)は以下のように計算します。

f:id:hiyokosabrey:20181105235722p:plain

切り出したい大きさを、テクスチャのサイズで割ると求められます。

f:id:hiyokosabrey:20181106000103p:plain

 

もっと大きなテクスチャでも基本的に計算方法は同じ。

ただし下図のように左上に配置していない場合はオフセットの値が必要になります。

f:id:hiyokosabrey:20181106231325p:plain

 

 UV値は0~1の値なので、小数を扱うことになります。テクスチャサイズで割り算することになるので、配置場所や面積(パーツのサイズ)は極力偶数にすることをオススメします。奇数だと割り切れないため誤差が生まれやすく一部のピクセルがキレイに描画されなくなったりします。テクスチャ圧縮がかかる場合は、さらに4で割り切れる場所にパーツを配置することをオススメします。後からテクスチャの解像度を変える場合でも偶数にしておけば安心です。

 UI表示はカメラに依存せず静止していることがほとんどなので、ピクセルが荒れていると目立ちます。面倒ですがこのあたりは丁寧に扱うに越したことはないです。

 

切り出すUVの範囲が分かったところで、今度はUVを動かす範囲を計算します。

f:id:hiyokosabrey:20181106233013p:plain

96をテクスチャサイズで割った値が移動量です。テクスチャサイズが 256pxだと、0.375 になります。

 

この移動をUMGのアニメーションで動かします。

f:id:hiyokosabrey:20181110130919p:plain

 

まずはTextBlockと共にキャンバスに配置します。

f:id:hiyokosabrey:20181107010948p:plain

トグルスイッチのテクスチャは、画像ではなくマテリアルをセットします。

f:id:hiyokosabrey:20181107213120p:plain

 

TextBlockには is Variable のチェックを付けておきます。

 

 

次にアニメーションを作成します。

Imageパーツの Pivot の値を 0.0 ~ 0.375 でキーを打ちます。

f:id:hiyokosabrey:20181107212722p:plain

UMGはここまでです。

 

エディタウィンドウをGraphに移動してブループリントを編集していきます。

f:id:hiyokosabrey:20181107213947p:plain

 常時走る EventTick を使っていますが、トグルスイッチなどのUIパーツはセッティング画面で使うことが多いので、ポーズ中とかゲームプレイ以外だと、それほど問題にならない、はず。Pivotの値を取り出して、毎フレームマテリアルのパラメータに渡しています。

 少しでも処理をシンプルにしたいので、コストの高いGet Dynamic MaterialノードはTickに入れないようにして、Event Construct で最初に変数化しておいたものを利用します。

 次に、トグルスイッチを動かすイベント。

f:id:hiyokosabrey:20181107222540p:plain

 UIのインタラクションはユーザーの操作で割り込まれるのが常なので、割り込まれても問題なく動くようにします。 なるべくアニメーションの尺を短く作るのも大事。

 

 最後に、初期値をもらって反映する関数。

f:id:hiyokosabrey:20181107223147p:plain

トグルスイッチのWidgetは完成です。

 

次は管理とレイアウトの仕組みを作っていきます。

管理はプログラマでなくても扱える ストラクチャ (構造体)ってやつを使ってみます。

f:id:hiyokosabrey:20181110131023p:plain

コンテンツブラウザから作成してエディットします。

f:id:hiyokosabrey:20181107223709p:plain

 

New Variable ボタンをクリックして名前との型をセットします。

f:id:hiyokosabrey:20181107224428p:plain

Saveして閉じます。

 

新しくレイアウト用のWidgetブループリントを用意します。

f:id:hiyokosabrey:20181110131119p:plain

 

キャンバスに用意したトグルスイッチのWidgetを並べます。

f:id:hiyokosabrey:20181107224827p:plain

 

Graph エディットに移行して、

変数を一つ用意します。

Variable Type を 先ほど作ったストラクチャ にします。

f:id:hiyokosabrey:20181107225412p:plain

 このストラクチャ型の変数をグラフに取り出したら、Breakノード経由で中の値にアクセスできます。今回はブーリアンばっかりですが、いろんな型をひとまとめに扱うこともできます。

 値を取り出してキャンバスに並べたトグルスイッチのWidgetに渡します。

f:id:hiyokosabrey:20181107225858p:plain

これで初期値とラベル名がセットされます。

ここで一旦画面で確認してみます。

このWidgetを保存してレベルブループリントから表示させます。

f:id:hiyokosabrey:20181107231302p:plain

 右の赤いブーリアン型のノードは、 エンジンに最初から用意されているパラメーター設定用のノードで、PlayerController から取り出します。

再生するとこんな感じ。項目の名前とストラクチャの初期値が反映できています。

f:id:hiyokosabrey:20181107231724j:plain

 

仕上げにマウスイベント。

クリックしてスイッチを切り替える処理を用意します。

GraphエディタのFunctions 欄 にある Override ボタンを押して、

On Mouse Button Down というのを選択。

f:id:hiyokosabrey:20181107232718p:plain

特殊な関数を編集できるようになります。

 

あらかじめ引数と戻り値のピンが設定されていて変更できない作りです。

f:id:hiyokosabrey:20181107233014p:plain

Warningが出ているので、黙らせるには、Unhandledノードをつないで・・・

f:id:hiyokosabrey:20181107233449p:plain

コンパイルすると鎮まります。

この関数は、自身のWidgetの上で、マウスのクリックが検出されたら呼び出されます。

白いラインの間にPrint Stringノードを入れて再生してみると分かります。高速でクリックしても反応しないのは、ダブルクリックと区別するためで、ダブルクリックはまた別の関数で処理することができます。

ここに、トグルスイッチのWidgetをクリックしているかどうかの判定と、スイッチの切り替えの処理を並べます。

今回スイッチが4つあって、全体はこんな感じです。

f:id:hiyokosabrey:20181107234617j:plain

マウスクリック系のイベントはひとまとめにできます。

 

基本的に、クリックした瞬間、カーソルは誰の上に乗っていたのか?をチェック。

f:id:hiyokosabrey:20181107235123p:plain

カーソルが乗っていたらどうするか? こうします。

f:id:hiyokosabrey:20181107235718p:plain

ストラクチャ型の変数から取り出した値をひっくり返して入れ直します。

Not ノードを使うと、ブール値は反転します。

 

これで完成です。

f:id:hiyokosabrey:20181108002615g:plain

 

 今回はプログラマとデザイナのブループリント編集がなるべくぶつからないように安全に触れないかな、と考えながら試作しました。

基本的に

 デザイナは見た目を担当。受け取った値を反映するとこまで。

 プログラマは並んだ各パーツを管理してシステムの値と連携するところ。

 

今回のアセットをそれぞれで担当を分けるとしたらこんな感じです。

f:id:hiyokosabrey:20181110125426p:plain

 この辺を考慮してイベントディスパッチャーを使わない仕組みです。

 UIパーツの方にマウスイベントの検出を入れると、イベントディスパッチャーを Call する処理と、管理側のWidgetBPからバインドが必要で、そこそこ連携しないといけないので、メンテナンスや調整のとき編集がバッティングしやすかったり、デザイナとプログラマとのコミュニケーションコストがそれなりにかかるのが予想されます。

 あと、マウスイベント処理をある程度まとめてON・OFFしたり管理できないと、後から条件がややこしくなるので、それを避ける狙いもあります。

 

 UIの見た目は自由にUIパーツの方で受け持って、設定画面を抜けるときに、UIパーツから最終の値を全て回収するという方法も考えられますが、UIパーツの状態を見てリアルタイムに反映させたい場合(サウンドのボリュームとか)は難しいし、値の回収を失敗する可能性を考えるとかえって手間がかかりそうです。

 他にも効率的で安全な作り方がありそうですが、いったんこんな感じでいかがでしょうか?

 

 トグルスイッチUIがたまたまいい感じになっただけだと思うので、もうしばらく検証していこうと思います。今までゲームパッドとかのコントローラ操作をメインに考えてきたので、マウスやタッチ操作にも馴染んでいかないとね。マルチプラットフォーム対応はUI泣かせですし。

 

ではでは

ステキなトグルスイッチライフを!

 

f:id:hiyokosabrey:20181110133023p:plain

 

 

 

 

 

 

 

 

 

ぷちコン応募作品のプロジェクト公開について補足

 台風24号がこちらに向かっている中記事を書いていますが、また停電は嫌なので遅筆ながら急いで書きます。

 UE4ぷちコン第10回、残念ながら選に漏れてしまいました。サクッと作ってみてそこからネタ拾っていけたら記事にしよう、と考えていたのでそこはまぁまぁ達成できたのではないかと。結果発表後の動きで応募作品を公開されている方がいらっしゃるのを見て、私もソワソワしてきて公開することにしました。Twitterにはすでに呟いていたりします。

f:id:hiyokosabrey:20180930093128p:plain

Puchi_MMAn_nin.7z - Google ドライブ

ファイルサイズは約44.5MB

UE4のVerは 4.20

 

作品内容についてはこちら↓

www.youtube.com

 

公開することについて

 結果発表で触れられてもいないのに公開って、どんだけ自信ありまくり?という声が聞こえてきそうですが、内容についていくつかこのブログに載せているのと、その記事を読んで興味を持ってもらえたなら動くサンプルとして見ていただたらいいなと考えて、プロジェクトごと公開するに至った次第です。

 なるべく見やすくノードを整理しているつもりですが、ごちゃついていたり、もっと最適化できそうな部分などが結構残ってます。ブループリントのようなビジュアルスクリプティングでは、テキストベースの共有ほど手軽じゃないので、ノード構成や最適化の研究って、直接触りながらの方がいいのかなと思ってたりします。

 あくまでもブログ記事と連動したサンプルとして公開してます。UE4での動作確認は行っていますが、プロジェクトデータによる問題等が生じた場合は、Epicではなく当ブログへコメントいただくか、Twitterアカウント @MMAn_nin の方へご連絡いただけると対応します。

 

 わりと簡単にプロジェクトを切り出して「ほい」って上げられるのは嬉しいのですが、いくつか気になったことがあって、急ぎ上げ直すことになりました。その理由としては以下。

 

ソースパスが見えちゃう

 エンジンにインポートする素材は修正したらすぐに手軽に再インポートできるので、こまごまとブラッシュアップするには大変手軽で嬉しい機能ですが、参照している場所の情報「ソースパス」を晒すことになります。

 特別に意識して対策していないと、Windowsのログオン名がファイルのパスに含まれてたりするので、うっかり、というのがあります。家だと趣味丸出しの厨二ワードだったり会社だと何かしらの管理IDだったりするかもです。

 この辺、外に切り出す際に、受け渡しに不要なフォルダ(Developersとか、IntermediateとかStarterContent)をフィルタリングしたり、ソースパスを偽装するかNullにするようなツールか何かがあるとありがたいと思うのですが、どこかにあるのかな?。 

 余談ですが、Unityはエディタ内に再インポートの仕組みがないのは、この辺の情報を抱えたくなかったからなのか、という気がしてる。

 

 

再配布可能かどうかの確認が必要

 プロジェクトデータに限った話ではないですが、外部のフリー素材を使っているコンテンツを公開する場合、あらかじめ利用規約はしっかり理解しておく必要があります。提供元によっては許諾範囲に制限があることがあります。 製品だと、クレジット画面などで表記する機会が用意できますが、プロジェクトデータの状態でとなると、触れる機会が無いので、ひとまずといった対応ですが、著作権表示および提供元サイトへの誘導としてサイト名とURLを書いたテキストファイルを一緒にアップしました。ファイルの場所は プロジェクトフォルダの直下です。

 確実に目に留まる場所ではないので、その対策のひとつとしてこの記事を書いています。

 今回の公開データで素材が気に入った場合は、ぜひぜひステキな素材提供サイトをご利用ください。

 

《BGM》

musmus.main.jp

 

《SE》

soundeffect-lab.info

 

 

作品について

 今回ゲームとしてワクワクするところのないアイデアだったので、次回はもっと盛り上がれる要素を入れていけたらいいなと思ったりしています。ちゃんと動くものを作ろうという点ではそれなりにカタチにできたので満足しています。

 ボリューム的にいろんなものを短期間で用意しないといけないので、サクッと作れるようにもっと使いこなさなければ、と決意を新たにしました。とはいえ範囲が広すぎるので、気になるところから地道に触っていくしかできませんけどね。参加できる限り参加していって、提供できそうなネタがあれば記事にしていこうと思います。

 

 おっと、ずいぶん台風が迫ってきました。今回も影響が大きそうなので、身の安全を第一に過ぎ去るのを待つことにします。明日みなさまが青空を無事に迎えられますように。

 

私は月曜の朝から胃カメラの予約があるので憂鬱ですw

 

ではでは

ステキなUE4ライフを!