【UE5】Enhanced Input:Priority や Consume Input の検証
皆様、あけましておめでとうございます!!
今年も一年宜しくお願い致します!
2022年で一番触ったはずの Enhanced Input が未だによく分かっていません。
すべての始まりである「Add Mapping Context」も初心者の私にはややこしかったため、色々確認したことをまとめた記事になります。
【この記事の内容を YouTube の動画で公開】
https://youtu.be/j8pUpNu8CuE
「Input Mapping Context」を記載するのが長いので、以降 IMC と記載しています。
Add Mapping Context
Enhanced Input を触った時に一番最初にお世話になるノードだと思います。
機能としては "Mapping Context" で指定した IMC を追加し、入力を使えるように準備します。
"Priority" で入力の優先度をつけることができます。
数字の大きい方が優先度が高くなります。
2023-01-02 追記:
"Options" ですが、とても重要なオプションであることが分かったため追記致しました。
どういうオプションなのかについてページ下部の「Ignore All Pressed Keys Until Release」に追記しております。
抑えておくメインの機能についてはたったこれだけです。
これだけなんですが、どういう挙動を示すのかを見ていくと意外とややこしいです。
しかも Enhanced Input を使う上で絶対理解した方がいい挙動ばかりでした。
▼ Enhanced Input の公式ドキュメント
https://docs.unrealengine.com/5.0/ja/enhanced-input-in-unreal-engine/
公式ドキュメントにこのような記載がされています。
適用したコンテキストに優先順位を付けることで、同じ入力を受け取る複数のアクション間の競合を解決できます。
複数の IMC があり、それぞれで IA_Jump という同じ入力アクションを設定した場合、ジャンプボタンを押した時にトリガーされるのは1回なのか、複数回なのか気になりますよね。
この記事はその優先順位に注目しています。
そんなわけで下記いくつか検証を行ってみました。
検証の前に
今回の検証ではジャンプのトリガーを基準に見てみます。
まず IMC_A と IMC_B の2つを用意し、両方に入力アクションの「IA_Jump:スペースバー」を割り当てています。
IMC_A は Triggers に Pressed を指定しています。
(Pressed はキーを押した瞬間トリガーされます)
IMC_B は Triggers に Released を指定しています。
(Released はキーを放した瞬間トリガーされます)
また、入力アクション IA_Jump には Triggers/Modifiers は設定していませんが、大事な設定なので "Consume Input" に赤枠をつけています。
最初は ON の状態で確認します。
トリガーの確認方法ですが、ジャンプがトリガーされた時「Print String」で "Jump" と出力するようにしました。
押した放したでどうなるか見ていきます。
検証1:IMC_A の優先度を高くする
「Add Mapping Context」の Priority を IMC_A が高くなるようにしました。
プレイして確認すると IMC_A の Pressed 入力が優先され、スペースバーを押した瞬間に1回トリガーされます。
IMC_B の Released はトリガーされません。
検証2:IMC_B の優先度を高くする
今度は IMC_B の Priority が高くなるようにしました。
プレイして確認すると IMC_B の Released 入力が優先され、スペースバーを放した瞬間に1回トリガーされます。
IMC_A の Pressed はトリガーされません。
検証3:同じ Priority にする
今度は両方の Priority を同じにしました。
プレイして確認すると後で追加された IMC_B の Released 入力が優先されスペースバーを放した瞬間に1回トリガーされます。
IMC_A の Pressed はトリガーされません。
同じ Priority の場合は後から追加したものが優先されます。
ここまでの結果で、入力が被った場合は Priority の高い方が優先され、同じ場合は「Add Mapping Context」で後から追加したものが優先された入力になることが分かりました。
検証4:割り当てるキーが違う場合
今度は IMC_B のスペースバーの代わりにマウスの右クリックを割り当てました。
入力の被りがなくなった場合はどう処理されるかも見てみます。
結果は Priority に関係なく両方ともトリガーの対象になります。
IMC_A のスペースバー(Pressed)と、IMC_B の右クリック(Released)が両方とも利用できるということです。
同じ IA_Jump を使ってるので Priority の高い方が優先されるのかなと思いましたが、キー入力も完全に一致してる時じゃないと効果はないようですね。
この設定をちぐはぐにしておくメリットがあるのか分かりませんが、入力があっちもこっちも反応してる場合はこの辺りを見直したほうが良いかもしれません。
検証5:Consume Input とは?
※ IMC_A と IMC_B 両方ともスペースバーの入力に戻しました
ここまでの検証は "Consume Input" が ON でした。
OFF にするとどういう挙動になるかも見ていきます。
結果は Priority に関係なく両方ともトリガーの対象になります。
入力はどちらもスペースバーですが、押した瞬間、放した瞬間それぞれでトリガーされるということです。
"Consume Input" は入力が被ったキーがあった場合、優先度が低い入力も処理するか?という設定になることがわかりました。
2023-01-03 追記:検証6:複数の IMC で入力アクションは異なるが同じキーを割り当てた場合
今度は IMC_B に違う入力アクション IA_Jump2 を割り当て、キーはスペースバーで同じキーを割り当てました。
入力イベントは異なっているが、割り当てたキーは同じというシチュエーションです。
この結果は Priority の高い方が優先されます。
それぞれの入力イベントでトリガーされるだろうと思っていたので意外でした。
検証の結果
ここまでの結果で、Enhanced Input の入力は、入力アクション(IA_○○)よりも割り当てたキーが被っているかどうかを優先的に判断し、その結果を Priority や Consume Input に準じて処理するという結果になっています。
入力が競合しないようにと、簡単に書いてましたが、
細かい挙動はドキュメントを見ただけでは分からない内容ばかりでした。
ただ追加するだけですが、設定によって色々なパターンがあることが知れて非常に勉強になりました。
IMC はキャラ移動用や UI 操作用など、ゲーム内で必要な新しい入力を追加することができるので、優先度について知っておくことは今後必要になると思います。
おまけ1:Remove Mapping Context
"Mapping Context" で指定した IMC を削除します。
IMC がなかった場合はエラーや警告もなさそうでした。
主に「Add Mapping Context」で追加した IMC を削除する時に利用することになると思います。
一例ですが、インベントリを開いた時に 「Add Mapping Context」で UI用の入力を追加し、閉じる時に「Remove Mapping Context」で削除するような使い方が出来ます。
IMC がアセット単位のためこういう付け替えが容易にできるのは非常に嬉しい機能です。
おまけ2:Clear All Mappings
追加したすべての IMC を削除できます。
ゲーム中タイトル画面に戻ることを想定した時、色々な IMC が追加されていることも予想されるため「Clear All Mappings」で綺麗にしてから必要な IMC だけ「Add Mapping Context」をするなどの初期化系の処理に使えそうです。
2023-01-02 追記:"Options"ピンの Ignore All Pressed Keys Until Release
先に Twitter へのリンクを貼っておきます。
https://twitter.com/UE5wancoro/status/1609488690421837825
どういうシチュエーションなのかというと
IMC_A に IA_OpenPauseMenu という入力アクションを用意し、Escキー(Pressed)で Pauseメニューを開くという実装をしました。
Pauseメニューを開く際、Pauseメニュー専用の IMC_Pause を「Add Mapping Context」で追加します。
IMC_Pause には、IA_ClosePauseMenu という入力アクションを用意し、同じく Escキー(Pressed)で Pauseメニューを閉じるという実装しました。
Pauseメニューを閉じる際、IMC_Pause を「Remove Mapping Context」で削除します。
こういうシチュエーションで、IMC も入力アクションも Open/Close で違うけど、両方同じキーを割り当てたという内容です。
Escキーで Pauseメニューを開くと、なんとメニューが開く→ 閉じる→ 開く...と Escキーを押しっぱなしの間これがループします。
「Add Mapping Context」で違う IMC を追加したにも関わらず、入力アクション(入力イベント)も違うのに、入力はフラッシュされず押した状態が継続しているということになり普通にまずい挙動です。
期待していた動作は Escキーを押せばメニューがちゃんと開き、もう一回押したら閉じるという動作です。
その前に、この動作については historia 様が公開して下さっているこの記事で解決できます!
本当にありがとうございます!!
▼ [UE5][C++]EnhancedInputで独自のInputTriggerを作る~UIカーソル高速移動編~
https://historia.co.jp/archives/26608/
補足となりますが「Add Mapping Context」「Remove Mapping Context」の "Options" は「Modify Context Options 構造体」となっていて、画像のようにピンを分割することができます。
右側のようにピンを分割するか、「ModifyContextOptionsを作成」ノードを使うと出てくる "Ignore All Pressed Keys Until Release" のフラグにチェックを入れれば先程のメニューが開いて閉じてのループはなくなります。
注意したい点は "Options" ピンが結合されている状態だと先程のループする症状が発生するということです。
"Options" ピンを分割するとデフォルトでチェックが入っておりループはしません。
恐らくデフォルトで "Ignore All Pressed Keys Until Release" が False になっていると思われるので、明示的に True にしておく必要があるようです。
今まで使った事がなかった "Options" ですがこんな大事な設定が隠れているなんて思いませんでした。
これを知らずにデバッグしても解決策は見つからなかったと思いました。
押しっぱなしで反応してもいいケースや、そういう挙動にならないケースであれば False でいいと思いますが、これからは「Add Mapping Context」と「Remove Mapping Context」の "Options" ピンは分割し、True でも False でも明示的に設定しようと思いました。
年明けからまた勉強になりました。
「Add Mapping Context」は追加と Priority を決めるだけで簡単に利用できるためか、細かい検証をしている情報には辿り着かなかったためこの記事を公開してみました。
今年は一本ゲーム完成を目指したい所です!!