UIへの対応

山村達彦氏(以下、山村):次にUIへの対応もやっておきましょう。

Steamなどに持っていったUnityのモバイルのゲームでUI対応していないものがけっこうあって、気になっています。それはInput Systemに限らないんですけどね。UIのイベントを取るためにはイベントシステムが必要ですが、Input Systemを導入した状態でUIを使おうとすると、エラーを起こすんですね。現行のUnity Input Managerにしか対応していないという話で、Input Systemに対応させる必要があります。

Replaceボタンを押せばInput Systemに切り替わります。このInput Systemの操作をよく忘れるんですよね。それで「エラーが起こっているんですけど」と言われて。Input System UI Input Moduleというものを設定すると、Input SystemのInput Actionsに登録されている中から、UIに対するアクションを設定できます。これは基本的に、全部PassThroughでやる必要があります。

もしInput Systemではなく自分のものを使いたい場合、実はUIの中身を全部移植すれば動かせます。

(スライドを示して)例えばこんな感じですね。

ただ、これはあまりやる必要がないと思っていて。基本的にはデフォルトのInput Systemで取るので十分です。

UI Input ModuleとCameraを使った設定

1個だけ使うケースがあって、例えば、ローカルマルチプレイでInput Systemのキャンバスで複数のUIを持っているケース。Player Inputが複数あって、それに対応するUIも複数あるケース。そういう時はこのUI Input ModuleとCameraを使って設定します。

Actionsを設定して、Action MapsにUIを追加して、Ponter Behaviorに設定しているものと、Actions Assetに設定しているものを同じにした上で、このPointやLeft Click、Submit、CancelをMy Controls(Input Action Asset)が持っているアクションを使って設定していきます。

これだと基本的にはInput Systemでメニューを開いている時に、キャラクターを動かせちゃうんですよね。これはデフォルトの設定でも同じですが、例えば今メニューを出していますが、この状態で動かすとできてしまう。

では、どういうふうに対策すればいいのかという話ですが、要するに、メニューが開いている間にUFOのDefault Actions Mapをキャラクターが動かせないようにすればいいんです。例えばこの場合、Default Actions Mapがバトルかノーマルだとキャラクターを動かせますが、UIに変更してやると動かせなくなります。

逆にUIを反応させたくない場合。ここがやっかいで、正直バグだと言ってもいいような気がするんですが、UIのInput Moduleに登録されているイベントって、タイミングによっては強制的にオンにされてしまうんですね。なので、基本的にはInput Systemのモジュールを止めてしまうのが一番簡単にできます。

2時間ぐらい前だったら、「UIを切り替えたりして」って本当は言いたかったんですが、さっきちょっとやったらポイントが勝手にオンにされてしまっていることに気づいてしまったので。残念ながら基本的にはInput System自体をオフにしてしまうのが一番手っ取り早いという結論に至っています。

逆に、UFO自体を止める場合は、Default Actions Mapを切り替えればいいのでそんなに難しくない。それを採用しているのがこのメニューで、先ほどと似たような感じですね。通常時にEscapeか、もしくは△ボタン、キーボードとGamepadでOpenMenuというものを実行する。とりあえずこれで、メニューを表示してInput SystemのActions Mapを切り替えるということを書いてみました。

まず、UIが開いていない時はOpenMenuができて、開いている時はCloseMenuができるという状態で、OpenMenuにしたらユーザーの操作モードをUIにして、その上でシーンをロードして、クローズしたらUIの操作モードをノーマルに直す。もしくは、直前に使ったActionsモードにして、シーンをアンロードするようなことをします。

そうすると、今Gamepadを上下左右に押していますが、メニューを表示するとキャラクターが動かせなくなって、解除すればキャラクターが動かせると。

Devicesを見てもらうとわかりますが、今どんなデバイスを使っているのか(の情報)をDevicesで取れています。もしくは、コントロールのバインディングの対象でもデバイスが取れたはず。

とにかく、UIを受け付けるにはイベントシステムが必要で、そのイベントシステムが使うポイントやクリックは、基本的にAction Assetsで設定しておきます。その上で、UIを表示している時に動かせないようにする場合は、一番手っ取り早いのがAction Mapsを切り替えてしまうこと。そうすれば、UIを操作している時はバトルモードの移動やFire、ノーマルモードのDashなどができなくなります。

キーコンフィグの挙動と設定

UI対応もできたので、最後にキーコンフィグの話もしましょう。

これがすごくややこしい話で、キーコンフィグ自体は、マニュアルの「How do I...?」で説明されているPerformInteractiveRebindingで実現できます。

ただこれがすごくやっかいな機能で、やっていることは、基本的にはInput Actionがバインディングしている細かいアクションを、ほかの操作で上書きするという挙動をします。その動き方がちょっと独特というか、パッと見わからなくて。(スライドを示して)基本的にはこんな感じです。

リバインディングのアクションを起こすと、いったん別スレッドで始まってバインドするまで処理を実行して、バインドが完了したらアクションを更新して再開する挙動をします。

なので基本的には、処理をアクションでリバインドする前にいったんアクションを止める必要があります。

アクションを止めてリバインド処理を開始して、ほかのデバイスを登録待ちして、ほかのデバイスの登録が完了したらアクションや(ゲーム操作の)受け付けを再開する、みたいな処理を記述する必要があります。

その上でやっかいなのが、これはリバインドを開始して終了したらオペレーションを削除してをやっていますが、特になにも設定しなかった場合、このアクションに対して同じバインディングで中身を上書きしてしまいます。これは、Gamepadとキーボードとタッチパネルに接続しているんですけれど、コードを実行すると(同じアクション内のすべてのControlの中身を)全部上書きしちゃう。

なので、バインディングをする時に、バインディング可能なデバイスや対象を、いろいろな条件で制限する必要があります。例えば、接続している対象の何番目に対して上書きをするみたいな制限や、入力をする時に特定のキーだけはバインディングできないようにするとか。そんな感じですね。

基本的には、キーコンフィグの場合はまず.WithTargetBindingと.WithControlExcluding呼んで、どのアクションのどのバインディングに対してどのキーを割り当てる、というのをインタラクティブで実行して、受け付けて反映してアクションも更新という感じになります。

(スライドを示して)これはすごく単純にしたコードです。

ここで、どのアクションに対してなにかをするのかを設定します。

コンフィグが開始されたら、いったん画面をコンフィグ画面にして、指定したアクションに対してバインディングを開始して、更新する対象のSchemeは.WithTargetBindingで、△ボタンかコンフィグボタンだけは押さないようにしてみたいなことをやって、キーコンフィグを行います。

実際に動かしてみると、今はOpenMenuでコンフィグメニューを開くようになっています。ボタンを押すとコンフィグボタンが開始されて、オーバーレイのスクリーンを表示します。これはもうasyncの処理ではないので即座に終了してしまっていますが、基本的にはコールバックで終了まで待っています。

RBボタンを切り替えてやれば、キーコンフィグができます。

キーコンフィグができたのはいいですが、それが毎回(ゲームを終了する度に)消えてしまうのはよくないので、保存が必要です。そのためには、アクションをJsonに変換して保存して、保存したJsonをロードすると復帰できます。ポイントはアクション丸ごとではなくて、オーバーライドしているところだけという点。つまり、この処理でキーコンフィグをした場合、その中身の部分だけをJsonとして書き出せます。

このようなAPIが最近追加されています。これ(サンプルコード)は本当に単純で、PlayerPrefsにJsonを格納しておいて、持っているアクションに対して起動した時にすでに設定があればロードして上書きするし、ゲームを終了する時にインプットがあれば、セーブでJsonにしてしまって、それをPlayerPrefsに保存する。

そういうことをすればいいです。「レジストリに保存するのでPlayerPrefsはあまり使うべきではない」という意見もあるにはありますが、キーコンフィグの場合だったら使ってもいいんじゃないかなとは個人的には思います。

ちなみにデータを消す場合は、ContextMenuを登録しておくと(エディターメニューから)破棄できるので楽です。

Input Systemは設定がややこしいが、理解すると使いやすいと思えるかも

ということで、今回話した内容です。射撃をするためのInputActionで複数のデバイスに対応することや、コールバックの話、Initial State CheckやPassThroughの動作ControlSchemeを使って、同じような動作にするための複数のデバイスがあった時に、そのデバイスごとに挙動を作っていく方法、Action Mapの切り替え、UIの対応、最後にキーコンフィグの話をしました。

今回話す内容はここまでですが、どうでしたか。Input Systemは設定がややこしいところもまだ多いといえば多いですが、PassやControlSchemeの話を理解すると、「おっ、なんか使いやすいな」と思う時もあるんじゃないかとちょっと期待しています。

PerformInteractiveRebindingで複数キーをバインディングできるか?

(コメントを見て)「PerformInteractiveRebindingでone modifierなど複数キーをバインディングできますか?」。いいことを聞いてくれました。ありがとうございます。まとめる前に話しておきましょう。

キーバインディングに関して、今回どういうふうにやっているのかという話をしましたが、実を言うと、Input SystemのSamplesの中にあるRebinding UI(のサンプル)は非常に優秀です。

この中にキーバインディングのCompositeの対応も入っていたはずです。バインディングをしている時に奥に行って、動作を確認するみたいな挙動です。例えば、Keyboard&Mouseでマウスをクリックすると、upの対応するキーはwです。downはs、leftはa、dみたいな。

あとは、先ほどの質問でもあったとおり、デバイスごとにアイコンを変えるみたいものがあって。ABXYか、△□×○か、(手持ちのゲームパッドは)どちらの勢力圏に所属しているかはちょっとわかりませんが…これは△ですね。もしくはABXYに所属しているデバイスだったらABXYになるみたいな。そういう(デバイス毎に表示をしてくれる)サンプルがあるので、特にバインディングに関しては、これを見てもらうとすごくわかりやすいと思います。

アイコンも入っています。ちゃんとどのデバイスかをチェックしてやっていますね。こいつ(別のサンプル)には先ほど話したセーブの話もあるので、参考にしてもらうといいと思います。

ということで、なにか質問があったら動画にコメントをしてもらえればある程度は回答できると思います。ほかにもInput Systemはけっこういいブログを書いてくれている方もいるので、そちらも含めていろいろ参考にしてもらえるとわかりやすくなると思います。それではご視聴ありがとうございました。