先日のツイートを一応メモっておきます。
スライダー道は奥が深いですね。
きっかけは @HirofumiSeo さんのこのツイート
Unreal Engine 4のUMGのSliderの設計(挙動)が、UIとして直感的ではないように思うのですが、設定でどうにか出来ますかねぇ。自分で画像とか駆使してスライダっぽい新しいUMGを作るしかないでしょうか。スライダハンドルを握ったときはハンドルは勝手に動いてほしくないですよねぇ。 #UE4 #UE4Study pic.twitter.com/DSIHCegVcK
— Hirofumi Seo 瀬尾 拡史 (@HirofumiSeo) 2021年2月12日
気になったのでいろいろ試してみるもドラッグ&ドロップでつまづいたので、取り急ぎ現行のスライダーを改造することにした次第。
ちなみに ちゃんとドラッグできるやつはこちらの @seiko_dev さんのツイート。
#UE4Study
— 恒吉星光 (@seiko_dev) 2021年2月20日
ツマミが握れるタイプのスライダーをやってみました。
確かに自作するとそこそこメンドイですね…!(構成はreplyにて)
挙動的にはScroll Barが近いと思うので、既存の部品からうまいこと持ってこれたりするかもしれませんね。
(C++ではUScrollBarというのがExprerimentalで存在した) https://t.co/R5LzedlXL3 pic.twitter.com/TtwfmxIwSB
素晴らしいです。
今までゲームパッドありきで考える習慣のおかげで、ドラッグ周りの仕様を触ってこなかったのが悔やまれます。
でぼくが作ったのはこれ。
スライダーを自作しようとしてみたのですが、なかなか手こずりそうだったので、思い切ってハンドルを非表示にしてシークバー風に改造。バーの部分はマテリアルでValueと連動させてます。左右に1Step増減のボタンを置いたらそこそこ使えそうな気がするのですが、どうでしょうね pic.twitter.com/wZbpPmJZNy
— みつまめ杏仁 (@MMAn_nin) 2021年2月19日
とりあえず作り方メモ
以前にも似たようなのを作ってましたが、ゲームコンフィグのような汎用性はいったん置きにして、1画面に1本想定、後からレイアウト調整がしやすいのを目指しました。
マテリアルパラメータコレクションを使います。
Scalarパラメータを追加。
このパラメータを使ってマテリアルを用意します。
CollectionParameterノードに、用意しておいたパラメータコレクションをセットします。黄色いのがゲージカラー、グレーが下地のカラーです。
1パラメータ1マテリアルになるので、画面に同時に表示するスライダの数ぶんマテリアルアセットを用意する必要が出てきます。同時に表示しないのであれば使いまわせます。
次にWidgetブループリント
まずキャンバスを用意
スライダーたちを格納する HorizontalBoxから
HorizontalBox に入れるUMGのパーツは3つ。
順番として Button → SizeBox → Button になるように入れます。
それぞれに子供として、
TextBlock と Slider を入れてます。
プロパティを触るのは最小限にしたいので、なるべくデフォルト設定でレイアウトします。
HorizontalBox は中身に合わせて自動的にサイズを合わせる Size to Contents を有効にしておきます。
スライダーの長さを調整する際の肝になるのが SizeBox
Width Override で決定します。
UMGでは、HorizontalBox の子として、直接 Slider を入れると Slider の持つ Canvas Panel Slot が置き換わってしまう仕様になってます。おかげでサイズがちゃんと認識されなくなってしまうのを解決するためにSizeBoxでくるむことにしました。
↓左が通常時、右がHorizontalBoxの子にしたときの状態。
このへんオートレイアウト系のしくみなので、おそらく何か理由はあると思いますが、スライダーのサイズ情報が別の Slot にあればよさそうではあります。
スライダーの長さは SizeBox に任せるとして、見た目を整えていきます。
スライダーのパーツはシンプルな構成で2つ。
Detail(詳細) パネルの Style の項目に Normal Bar Image と Hovered Bar Image があります。
Image のところに、用意しておいたマテリアルをセットします。
Normal は通常時、Hovered は マウスカーソルが上に乗った時を意味します。Normalの方の Tintカラーを少し暗くすると、操作したときに効果がわかります。
Disabled はスライダーが無効な時の状態ですが、条件的にあり得る場合はここにも同じようにマテリアルをセットしておきます。
Bar(溝) の下に 続けて、Thumb(つまみ)の設定と、Barの太さの設定。
つまみのビジュアルはここで消します。
Draw As を None にすることで描画はされなくなりますが、Image Sizeは生きていて、Barの見た目の長さに影響するので、ゼロ にします。
スライダーの長さにこだわるのは、スライダーで扱う最大値とピクセル表示量の差をできるだけ整数倍にしやすくするのが目的です。計算の仕組み上仕方がないと分かっていても、見た目に「わかる」「わからない」は重要です。にんげんだもの。
というわけで、エンジンのお気遣いは排除します。これで単純に SizeBox の値だけでコントロールできるようになりました。
スライダーの設定はこれで終了。
次は 再ヘッダ的なカレント位置を示す TextBlock
中央揃え にします。
数字と|は間に改行を入れて2行にしています。
行間は Line Height Percentage で調整できます。
ブループリントから書き換えるので、 Is Variable を有効にするのも忘れずに。
このTextBlockは ゲージの左端に合わせて座標を決めます。実際に動かす際は、RenderTransloation を使って相対的に動かすので、この初期位置だけを合わしておけばOK。
これでキャンバスの準備はできました。
次にWidgetブループリント
Float型の変数を作って、Event Pre Construct につないでセットします。
セットする値は、 SizeBox から取得します。
もう一つ スライダーの最大量を保持する Float型の変数を追加。
ついでにスライダーのプロパティもここで変更します。
スライダーの変更を見た目に反映する関数を作ります。
Bar部分にセットしたマテリアルを更新。
テキストの内容とポジションを更新。
ほぼこれで完成です。
試しに Event Construction に関数をつないで確認してみます。
レベルブループリントからViewportに追加して再生します。
あとはボタンを押したときの処理。
UI的には Numeric Stepper に相当します。
編集画面を Designer に切り替えて、Button のDetailタブ(詳細)からイベントを作成します。On Clicked のプラスボタンをクリック。
イベントグラフにイベントノードが現れます。
ここにクリックした際のふるまい(挙動)を用意します。
再生して確認します。
ついでにボタンのテキストも変えてみました。
改造は以上です。
実は UIデザイナー向けのポートフォリオをUE4で作ろうというプロジェクトを目論んでいるので、ちょうどよいものができました。
スライドの切り替え等に使えそうです。
ここからはスライダーに関しての考察とかなんとか
スライダーといえば、ゲームコンテンツの話に限ると、遊びやすさをカスタマイズするためのセッティング画面で見かけるものがほとんどで、その用途はたいてい音量を調整するためのもの。他の要素もスライダーの形式をとりつつも、ステップ(刻み)がサウンドほど細かくないので、スライダーである必要がなかったりします。
用途と操作するデバイスによって有利不利があるので、全て書ききるのは文字量がえらいことになりそう、というか今はちゃんと整理できてないので、またどこかでまとめてみたいと思います。
UE4 の UMGに用意されているスライダーは、音声ボリュームの調整を主用途として想定されている印象。
クリックした際に、ポイントした位置につまみが移動するのは、今の位置から微調整したいわけではないのでは?と推測します。音量って、ステップ(変化の刻み)が細かくてちょっと動かしたぐらいでは、差異がわかりにくいのもあるのかなと思います。
よく見かける3つのボリューム SE、BGM、VOICE のバランスをミキサーのように扱うからこそのスライダーだと考えると、精度というよりは比較を優先しているのかなと。
また、スライダーUIにとって、つまみの大きさと見た目は大変重要です。
マウスのような手首や腕で操作するデバイスでUIを細かく操作するのは、なかなか鍛錬が必要ですし、ゲームパッドに至ってはスライダーはフリーカーソルと並んで操作が面倒なUIの上位にくるやつです。それぞれでつまみに対する最適なサイズがあります。
今回の事案で、いくつか設定されている機能要件の中に、
つまみをマウスボタンで押下しただけでは動かない
と
つまみ以外でクリックしたらその場所につまみがジャンプする
の2つがあります。
仮に一つ目の要件を満たしていたとしても、
つまみのサイズ小さくしすぎるとカーソルを合わせにくくなり、ジャンプしやすくなるので要件を満たすのは難しくなります。
大きすぎると、そのぶん離れた位置にしかジャンプできなくなります。
なかなか興味深い悩みです。
つまみの大きさについては、マウスを操作する方のシチュエーションとスキルによって決めていくことになると思います。
センサーの分解能や、カーソルスピードも関係します。ボタンを押下したときにマウスが動いてしまうとかも対策が必要かもしれません。
モニタの大きさと解像度の関係も大事です。
こういった用途や使う人に合わせて細かいチューニングが必要なのが、UI開発の面倒くさいとこでもあり、また面白いとこです。
常に最適解を求めていくのが大事という志向なので、基本、「使いまわし」 は考えないようにしています。使いまわすのはパーツやアセットではなく経験則。
実際に試してみると、気づかなかったいろんな事象がチラチラするので、試行錯誤はやってやりすぎるということはないなと思っています。
にしてもUE4のドラッグ周りの仕様が少し見えてきたので、もっと検証してみたい。マルチプラットフォーム開発は、特定のデバイスに例外的に対応するのは避ける傾向があります。最大公約数というかベン図の重なったところで答えを見つけようとするので、どうしてもそのデバイスの性能をどこかで切り捨てているのも事実。パズルのようで難しいですがうまく解決できるように、いろんなアプローチを試していきたいですね。
なんか長くなりましたが今回はこの辺で
ではでは
ステキなスライダーライフを!