まえがき
モバイル向けにタッチ入力を検出するイベントが用意されている(↓参考)のですが、Widgetから利用することはできません。 yashinut.com
どうにかWidgetでタッチ入力を検出できないか調べたところ、関数オーバーライドを利用するとよいことが分かったので使い方を紹介します。
確認環境
- まえがき
- 確認環境
- Widgetの関数をオーバーライドする方法
- タッチ入力に関係する関数一覧
- タッチ系関数の紹介...の前に
- タッチ系関数の紹介
- タッチ系関数内で取得できる情報の紹介
- タッチ系関数をオーバーライドして使ってみる
- 参考資料
- あとがき
Widgetの関数をオーバーライドする方法
まず、タッチ入力を検出するためにはWidgetで関数をオーバーライドする必要があります。WidgetのBPで関数の横にある+マークにマウスをホバーさせると「オーバーライド」というプルダウンが出てくるので、そこからオーバーライドしたい(利用したい)関数を選びます。
ここで選択した関数は特定の処理が発生するとUE4のシステムから呼び出されるようになっています。そして呼び出された時の処理を関数内に書くことになります。
↑ではOn Touch Started関数をオーバーライドしました。この関数は指がWidgetに触れたときに呼び出されます。(タッチ系の各関数は後で触れていきます)
また、画像を見てわかるように内部の処理を書いただけだとリターンノードで警告がでてしまいます。(コンパイル時に発生します)
これを修正するには出力ピンにHandledノードかUnhandledノードをつないでやる必要があります。どちらをつなぐかは基本的に↓の考えでOKです。
- 関数内で処理を行った場合 -> Handledノードをつなぐ
- 関数内で何もしていない場合 -> Unhandledノードをつなぐ
タッチ入力に関係する関数一覧
↓に挙げる関数をオーバーライドしておくと特定のタッチ入力があったときに呼び出されます。関数名を見ればどんな入力があったときに呼び出されるのか想像がつく人もいると思います。
- On Touch Gesture関数
- On Touch Started関数
- On Touch Moved関数
- On Touch Ended関数
- On Touch Force Changed関数 <- 使い方を知らないので紹介を省きます
- On Mouse Enter関数
- On Mouse Leave関数
後半にOn Mouse Enter関数、On Mouse Leave関数が入っているのですが、これは書き間違いではありません。タッチ入力を検出したいのでOn Touch XXX関数だけ使うのかと思いきや、一部のOn Mouse XXX関数も関係してきます。
自分はいろいろ試しているうちにこれに気づきましたが危うく見逃すところでした...。
以降はここに挙げた関数をまとめて「タッチ系関数」と表記します。
タッチ系関数の紹介...の前に
タッチ系関数を使う際、いくつか注意点があるので紹介しておきます。
PCでタッチ入力をテストする方法
タッチはモバイル端末でテストするのが一番ですが、サクッと動作を確認したい場合はPIEを利用することになると思います。その場合PCでタッチ入力をシミュレートするために、マウス入力をタッチ入力として扱う設定が必要なります。
設定は↓をオンにするだけでOKです。
プロジェクト設定 > エンジン > インプット > マウスプロパティ > Use Mouse for Touch
タッチ系関数が反応する条件
タッチ系関数を反応させるには下記の条件が必要になります。
- Widget内にあるUIパーツのVisibilityがVisibleである
この条件を満たしてタッチ系関数をオーバーライドしないと、タッチ入力に反応しません。
自分は最初UIパーツのVisibilityをNot Hit - Testable(タッチに反応しない設定)にしたまま配置していたので、タッチ入力が取れずにつまずいていました...。
また、ButtonやSliderなど一部のUIパーツはタッチ入力を横取りされるので注意が必要です。なのでImageをVisibleにして配置するのが無難かなと思います。
↑の場合、Image(白色のところ)の上をタッチした時だけタッチ系関数が反応します。ButtonとImageが重なっているところをタッチすると、Buttonが手前にあるためタッチ入力を横取りされます。
逆に考えると、UIパーツの前後関係でタッチ反応範囲を制限できるので何か使いようがあるかもしれませんね。
タッチ系関数の紹介
On Touch Gesture関数
ジェスチャー入力がされたときに呼び出される関数です。
ジェスチャー入力ということは、フリックやピンチ操作も検出できるのか!...と期待してしまうのですが、実はこれ内部実装がほとんどされていません。 詳しくは下記ツイートのスレッドに書いています。(あくまで私個人の推察ではありますが)
Widgetの関数オーバーライドにタッチ関連のものがあったので試してみたけど、ジェスチャーだけ思ったように反応しなかった...(UE4.24で実験)
— K.Y. (@KumasanDebug) 2020年6月8日
・OnTouchGesture -> △(PIEだと長押しだけ反応した)
・OnTouchEnded -> ○
・OnTouchStarted -> ○
・OnTouchMoved -> ○ pic.twitter.com/3qm8tMfiyA
どうしてもジェスチャー入力を検出したいという人は、下に挙げた方法で我慢しましょう。
プラグインを購入する
よくおすすめされるのはMobile touches gesture managerとかUltimate Touch Componentsです。ジェスチャーを自前で実装する
プラグインのように多機能なジェスチャー入力を再現するのは非常に骨が折れるのですが、他のタッチ系関数を組み合わせればきっとできるはずです。
自分でもタッチ系関数を組み合わせてジェスチャー入力の検出に挑戦しました。対応したジェスチャーの種類は少ないですが、いつか記事にして実装例を公開できれば...と思っています。
todo:記事書いたらリンク張る [20/24/2/28 追記] それから時は流れ、UE5時代に突入してしまいました。UE5で再検証するのに腰が上がらず結局記事をかけそうにないです...すみません。
On Touch Started関数
指がWidgetを押したときに呼び出される関数です。
画面上ではなくWidgetのUIパーツ上を押したときに呼び出されることに注意してください。
On Touch Moved関数
指がWidget上で動いたときに呼び出される関数です。これを使うとスワイプ操作を検出できます。
On Touch Started関数と同様、画面上ではなくWidgetのUIパーツ上で指が動いたときだけ呼び出されることに注意してください。
On Touch Ended関数
指がWidgetから離れたときに呼び出される関数です。
On Touch Started関数と同様、画面上ではなくWidgetのUIパーツ上で離されたときに呼び出されることに注意してください。
On Mouse Enter関数
指がWidgetの内側へ入ったときに呼び出される関数です。(リターンノードが用意されていないので、イベントとして出現します)
On Mouse Leave関数
指がWidgetの外側へ出たときに呼び出される関数です。(リターンノードが用意されていないので、イベントとして出現します)
On Mouse Enter関数の逆ですね。
On Mouse Enter関数とOn Mouse Leave関数が呼び出されるタイミングのイメージは↓になります。
タッチ系関数内で取得できる情報の紹介
各関数が呼び出されたとき同時にタッチに関する情報が送られてきます。取得すると便利そうなものに絞って紹介します。他にもあるので、興味のある人はいろいろ探してみてください。
タッチした指の番号
Get Pointer Indexノードで取得できます。
1番目にタッチした指は0、2番目にタッチした指は1...という感じで値が割り振られています。
これをTouch Indexとして扱いたい場合は何段階か変換を挟む必要があります。
また、PCでテストする際は注意点がありまして「マウスポインタも指」として扱わることがあります。これはOn Mouse Enter関数とOn Mouse Leave関数で発生することを確認しています。
指番号としては10が割り当てられていますので、指番号で処理を分岐する際は気を付けてください。
タッチした座標(ビューポート上)
Get Screen Space PositionノードとAbsolute to Viewportノードを組み合わせて取得できます。
このノードで「ビューポート上の座標」を取得できるのですが、ビューポート上の座標とは画面左上からの座標のことです。座標のイメージは↓になります。
タッチした座標(Widget上)
Get Screen Space PositionノードとAbsolute to Localノードを組み合わせて取得できます。
(ただ、On Mouse Leave関数については送られてくる情報が足りないので使うことができません)
こちらのノードで取得できるのは「Widget上の座標」です。ちょっと伝わりづらいかもしれませんが、座標のイメージは↓になります。
スクショではWidget_Test1にタッチした座標を取得するよう仕込んであります。そして、Widget_Test1の範囲は緑枠線の部分なのでWidget上の座標とはこの枠線左上からの座標となります。
スワイプ時の移動量
Get Cursor Deltaノードで取得できます。
結構便利そうなのですが、試してみたところ精度が粗いです。感覚としては小数点以下が切り捨てられているようでした。それでもOKという人はこのノードを使いましょう。
より正確な移動量を取りたい場合は自前で計算するほうがよさげです。実装としてはスワイプ時に前回タッチした座標と今回タッチした座標の差分をとればいいかなと思います。
タッチ系関数をオーバーライドして使ってみる
この記事のおさらいの意味も込めて、Widgetでタッチ入力を検出する実装例を書いておきます。ここまで読んで手元で試してみたけどタッチ検出できなかった...という人は、ここに書いた手順通りに進めてみてください。
(PCでテストしたい人)マウス入力をタッチ入力として扱う設定をオンにする
Widgetを作成し、Imageを配置
配置したImageのVisibilityがVisibleになっているかを確認
使いたいタッチ系関数をオーバーライド
任意のレベルを作成し、自作したWidgetを表示するようノードを組む
ゲームを実行して動作確認!
参考資料
- UE4 スマホ用インプットタッチノード解説 | やしなっつ
- UE4 UMGで入力を取得する - GameProgrammar's Night
- イベントでHandledを返して標準操作を無効化する - 妹でもわかるUnrealEngine4
- UE4モバイルブートキャンプ | PPT
あとがき
タッチ系関数でOn Touch Gesture関数が使えないのは残念...。でも、指が押された、動いた、離されたことさえ検出できればジェスチャー入力の疑似実装はできるので、まぁいいかなとも思ったり。
あとジェスチャー入力を自前で作っているときにOn Touch XXX関数だけを使っていると、Widgetの外側で指が離された場合にOn Touch Ended関数で検出ができなくてすごく困ることがありました。が、On Mouse Leave関数で対処できることを発見したときは感動しましたね。関数名だけ見てタッチに使えそうなものを選んでいたので盲点でした。