みつまめ杏仁

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

ボタン長押しゲージを作ってみた《ボタン編》

前回マテリアルを使ったゲージができたので、ボタンの表示とUI用のロジックを作っていきます。一例としてサンプル程度に見ていただけると助かります。

 

limesode.hatenablog.com

 

まずは簡単なボタンテクスチャのアトラスを用意します。

 

これをマテリアルで切り替えるようにします。

テクスチャを4分割しているので、UVに 0.5を掛けています。あとはUV座標をオフセットとして移動できるようにパラメータをつなぐだけのシンプルなもの。

UVオフセットの変更方法についてはいろいろパターンがあります。状況に応じて使い分けたいところ。

今回はブループリントから直接アクセスして操作するので、マテリアルインスタンスは使用しないつくりにしています。

 

新しくWidgetブループリントを作って、必要なパーツをキャンバスに配置します。

  • ボタングラフィック
  • ゲージ(前回の記事で作ったやつ)
  • ブルーム(強調用)

 

ここに長押しを示唆するパーツを追加

まだ一般的に長押しを促すシンボルなどは定着していないと思うので、自分なりに考えてみたものです。

 

この 4パーツを使って、4種類のアニメーションを作成します。

  • READY 準備
  • PROGRESS 進行中
  • ABORT 中断
  • ACCEPTED 受付完了

 

READY

長押しUIにとって無くてはならない演出。

ボタンを押下したタイミングで再生。尺はなるべく短くするのが大事。

今回は 0.17秒で作成しました。

ボタンを押した後で指を離すのがフツーなので、何かリアクション表現を見せて注目させるのが目的。ゲージが動き始めるまでの演出が長いと長押し操作に対してネガティブな印象を与えかねないので、ギリギリまで短くしたいところ。

 

 

PROGRESS

マテリアルのパラメータをUMGのトラックから制御できるのでそこで 1秒間のアニメーションとしてキーを打ちます。

ゲージの増加で打つキーの補間タイプは リニア にします。

このゲージが増えるだけのアニメーションを専用で用意するのは、再生速度を調整したいというのが理由です。

 

 

ABORT

指を離して中断した際のアニメーション

何事もなかったかのように元の状態に戻すだけの動きです。

 

 

ACCEPTED

最後まで押し続けたときに受理したことを表す表現です。

もう指を離していいよ、という意味合いになるので、それなりに感謝の意を込めるのがいいのではと思います。

次の状況への遷移があるので、あまり重い演出は避けたほうがいいと思います。

 

 

次にブループリントに進む前に、

今回使った Enum (イーナムとかイナムとか呼称されます)を2つほど紹介します。

あると大変便利なので、お勧めしたいなと。

コンテンツブラウザから右クリック Blueprints にあります。

まずはゲームパッドのボタン管理用

eHoldButton と命名

 

もう一つは、UIのステート(状況)の管理用

eUIState と命名

上にあげたのは一例です。UI設計に応じて追加したりしてメンテします。

 

 

ではボタンのブループリントについて

まずはキャンバスに置いた ボタン用 Imageパーツについて、Dynamic Material を準備

Event Pre Construct で作ることが多いです。

 

この Dynamic Material に対してパラメータを渡します。

その関数がこちら。

関数の入力にイーナムを使っています。

 

 

4番目はアルファ値(透明度)でマテリアルでは使いませんが、便宜的に 1.0 を入れています。

入れておかないと、ノードのプレビューが全部透明になってしまいます。

 

この関数は下のような形で使います。

外から直接呼ぶか、いったん変数に値を入れてから関数を実行するかはお好みで。

 

今回は、WidgetをViewportに描画する前に決まっている状態にしたかったので、変数をExpose on Spawn して運用しました。このケースだと、値を受け取るだけで実行はしないので、Event Construct でこの関数を呼び出しています。

イベント Event Construct は Viewport にAddされたタイミングで実行されます。

 

 

ここで今回ブループリント内で作った変数を公開

軽く用途を説明しておきます

  • MID_ButtonImage マテリアルアクセス用
  • CurrentAnim 最後に再生したアニメーションを保持
  • pregress_speed 長押し時間
  • faceButton ボタンの種類
  • UIState 処理状況管理

 

最後に再生したアニメーションを保持しておくと、別のイベントが割り込んできた際に状況確認がやりやすいので、個人的に気に入ってる方法です。

 

長押しボタンはキャンセルがいろんなタイミングで発生します。

また特定のアニメーション終了後に次のイベントに進むというのをやりたいので、Finishedイベントを多用しました。再生しきって終了なのか、アニメーションの停止なのか判別をつけるのが煩雑になったのもあって、ステート(状況)を管理する変数が、UIStateです。

 

というわけで、

メインのイベントを載せていきます。

 

 

ボタンを押したときのイベント

このイベントで READYアニメーションを再生します。連打されることもあるので、何かのアニメーションが動いていたら問答無用に止めます。何が動いていようが関係ないのが、WidgetAnimation型の変数で大変便利です。その代わり再生する直前で今から再生するアニメーションを変数に入れる必要があります。

 

 

長押し受付け開始

READYのアニメーションが無事に再生終わったということは、長押し継続という理屈なので、Animation Finished(****) イベントを利用して長押しゲージの進捗アニメーション PROGRESS を再生します。 ※ ****は対象のアニメーション名

この後の中断されたときのイベントで、UIStateの内容が変わります。中断されてこのイベントに来たら、READYからの流れじゃないということになります。

再生速度はここで反映するようにFloatの変数をつないでいます。

1.0で通常速度、 1以下でゆっくり、 1以上で速くなります。

 

 

ボタンから指を離した時のイベント

受け付けていない場合のみアニメーションを止めます。終了検知としてバインドしてるイベントが反応してしまうので、UIState を書き換えてから止めます。中断アニメーションを再生してまた次の開始を待ちます。

 

 

長押し完了イベント

これも長押しアニメーション PROGRESSが終了したら処理されるイベントになります。


イベント以上です

長押しボタンのWidgetはこれで一応動かせるようになります。

イベントディスパッチャー経由で、アニメーション終了を通知しています。

 

テスト

手っ取り早く試すためにレベルブループリントで直接動かしてみます。

 

呼び出すイベントは以下の2つ

 

30fpsでキャプチャしたGifなので、ちょっとぎこちないですが、今のところうまく動いてくれている様子。

Enumでステート管理すると、かなり状況把握がしやすくなると思います。

 

今回は以上になります

UI制作のヒントになれば幸いです

ではでは

素敵な長押しゲージライフを!

 

 

追記1

最初に実装し始めたころ、アニメーションの終了は SetTimerByEventを使って時間が来たら次のイベントに推移するようにしていました。

これだと割り込みが入ったときに、タイマーのリセットも必要で、対策していても、

何度かテストしていると、まれにタイマーリセットが間に合ってないのか、止めたはずのイベントが呼び出されてしまう事がありました。

仕方なくアニメーションの終了検知イベントが Widgetブループリントに用意されているのでそちらを利用することにしました。

上にも書いていますが、止まった理由がわからないまま終了検知イベントが動くので、対策として、ステートをチェックすることにして解決しました。

流れはシンプルなので、まさかこんなところで躓くとは想定してませんでしたが、結果的に思わぬ収穫になりました。やっぱり作ってみて気づくことは多いですね。

 

 

追記2

長押しは、気づかせるのが難しいのもあり、積極的な実装を見るようになったは、タッチデバイスの普及によるところが大きいのかなと思う。誤タッチ対策にもなるのでタッチデバイスとの親和性が高いのも手伝ってか、そこそこ見かけるようになった。気がする。

スマホのアプリを触っていると、キャラクターの多いアプリの場合、画面の情報量が多いので、遷移コストも相応に高そうなのも、無関係ではないと勝手に想像しています。

一方のコンソール系のゲームで長押しを導入するのは、あまり機会は少ないと思います。

よく見るのは、イベントシーンをスキップするとき。

せっかく時間とお金をかけて作ったイベントシーンをボタン連打でスキップされては堪らない、というのが制作側の本音としてあったりします。あとは世界観やストーリーを説明する大事な場面をスキップしてしまうと、ゲームの雰囲気に没入できないのではといった心配もあります。もちろんやりこみプレイで周回したときに飛ばしたい気持ちもわかるので、妥協点として初回はスキップできなくて一度見たらスキップボタンのナビが表示されてスキップできることが分かるようになるという仕様も見たことあるけど、見たか見ていないか、クリアしたかどうかみたいなチェックが面倒なので、わりとプログラマに敬遠される印象。その辺の事情もありやナシやで最近では、初回でも長押しでスキップできるようになるゲームが増えてきた印象。スキップする気はなくても、姿勢を正そうとしたり、コントローラを置こうとしたときにうっかりボタンに触れてしまい・・・というのも事故として報告は上がるので、なかなかうまくいかないですね。

 

最近はコンテンツも多くさっさとクリアして積みゲーを消化することが目的になっているプレイヤーもそれなりに見られますし、配信されやすくなったのも要因のひとつかなと思います。時代の流れというやつですかね。

ともかく イベントスキップについては、作る側と遊ぶ側とで議論の尽きない要素ではあると思います。

 

すこし話がそれましたが、

長押しの受付け表現としてはリングゲージとの相性が高いと思うので、このまま定着しそうですね。タップもしくはクリック位置から視線誘導もしなくていいし、そこを中心に時間経過を表現するので、起こっている事象と共にあとどれくらいそのままでいればいいのかがわかる。

長押しに気づけるかどうかという点では、

コンソール系はボタン操作のナビ表示があるので、まだ気づきやすいけど、スマホアプリは、どこを長押ししていいのか気づかせにくいのがUIデザイナーとして難しいな感じます。ハンバーグメニューみたいに、そのうちそれっぽいユニバーサル?なアイコンが発明されるのでは?と思ってます。

 

 

世間の長押しゲージについてはこちらの記事が参考になると思います

デザイン比較:長押しした時に表示されるゲージ - ゲームアプリのUIデザイン (hatenablog.com)