Input Systemでキーコンフィグを作っていて、コントローラーの入力を待つ処理をasync/awaitで実装したいの。
UniTaskを使ってこの辺を実装していく方法を解説していくね。
Input Systemのキーコンフィグでユーザーからの入力を待つような処理を実装する場合、次のようにInteractive Rebindingで実装する形になるでしょう。
参考:Class InputActionRebindingExtensions.RebindingOperation| Input System | 1.6.3
このように、ユーザーからの入力決定やキャンセルなどはコールバックとして通知を受け取る設計になっています。特にこのような非同期処理をシーケンシャルに書きたい場合、async/awaitで実装したほうコードの見通しが良くなる場合があります。
本記事では、UniTaskを用いて次のようにasync/await構文でInteractive Rebindingを扱えるようにする方法を解説します。
また、Interactive RebindingのキャンセルキーとCancellationTokenによるキャンセルに対応させるものとします。
- Unity 2023.1.8f1
- Input System 1.6.3
目次 非表示
前提条件
事前にInput Systemパッケージがインストールされ、有効化されているものとします。
ここまでの手順が分からない方は、以下記事を参考にセットアップを進めてください。
また、UniTaskをインストールしているものとします。インストール方法は幾つか存在しますが、UPM経由でインストールすることが出来ます。
UniTaskのインストールがまだの方は、以下手順でインストールを実施してください。
- トップメニューのWindow > Package Managerを選択し、Package Managerウィンドウを開く
- 左上の+アイコン > Add package from git URL…を選択
- URLの入力欄に以下を入力し、右側の「Add」ボタンをクリック
本記事の解説は、Interactive Rebindingによるキーコンフィグの応用編となるため、キーコンフィグの実装方法の基本を押さえておくと理解がスムーズです。
Interactive Rebindingによるキーコンフィグの実装方法は以下記事で解説しています。
コールバックをawaitに置き換える流れ
UniTaskのUniTaskCompletionSourceクラスを用いてコールバックを置き換えます。
参考:UniTaskCompletionSource Class| UniTask
まず、次のように待機の開始前などでインスタンス化しておきます。
そして、Interactive Rebindingを実行する時に、OnCompleteやOnCancelコールバックでUniTaskCompletionSourceインスタンスに対して結果の確定やキャンセルを通知します。
TrySetResultメソッドは結果の確定、TrySetCanceledメソッドはキャンセル通知を行います。
参考:UniTaskCompletionSource Class| UniTask
したがって、拡張メソッドとして実装すると、次のようなコードになります。キャンセル処理については後述します。
キャンセルキーへの対応
Interactive Rebindingでは、特定入力があったらリバインドをキャンセルさせる挙動が実現可能です。
前述の拡張メソッドに対して、次のように引数と設定を追加すれば良いです。
WithCancelingThrough拡張メソッドにキャンセル用のControl Pathを指定すれば、このControl Pathの入力があった時にキャンセル扱いになります。
参考:Class InputActionRebindingExtensions.RebindingOperation| Input System | 1.6.3
CancellationTokenへの対応
Interactive Rebindingのキャンセルに加えて、例えば画面遷移などその他の要因でキャンセルさせたい場合、CancellationTokenに対応させる必要があります。
これを行いたい場合、次のようにCancellationToken構造体を引数に追加し、CancellationToken.Registerメソッドでキャンセル要求が来た時にInteractive Rebindingをキャンセル(Cancelメソッド実行)させるようにすれば良いです。
InputActionクラスの拡張メソッドとして実装する
ここまでの流れを踏まえ、Interactive RebindingをUniTaskに変換するInputActionクラスの拡張メソッドの完成形の例を示します。
上記をInputActionExtensions.csとしてUnityプロジェクトに保存すると、拡張メソッドが使えるようになります。
使用例
以下、実際の使用例です。StartRebindingメソッドをボタン押下時など外部から呼び出すことでInteractive Rebindingを開始できるようにしています。
上記をAwaitExample.csという名前でUnityプロジェクトに保存し、適当なゲームオブジェクトにアタッチし、インスペクターより各種パラメータの設定を行います。
例では、Actionにキーボードの「1」キーがデフォルトで割り当てられ、キャンセルキーに「Esc」キーが割り当てられ、リバインド中に表示するマスクにオーバーレイの画像を指定し、タイムアウト時間を5秒に設定することとします。
また、UIのボタンなどが押されたときにStartRebindingメソッドを実行させることとします。
実行結果
ボタン押下でInteractive Rebindingを行うと、キーが変更されていることが確認できます。
CancellationTokenでタイムアウトを設定していますが、こちらも機能するようになっています。
スクリプトの説明
CancellationTokenによるInteractive Rebindingのキャンセルを行えるようにするため、CancellationTokenSourceをフィールドとして定義します。
これは、ゲームオブジェクトが破棄されたタイミングなどでキャンセル可能にするためです。
Interactive Rebindingの開始は、次のようにpublicメソッドを公開し、外部から呼び出せるような形にしました。
Interactive Rebindingの処理の開始時点では、次のコードでマスク用画像を表示したり、CancellationTokenSourceインスタンスを作成したりしています。
タイムアウト値は、CancellationTokenSource.CancelAfterSlimメソッドで指定しています。
参考:CancellationTokenSourceExtensions Class| UniTask
そして、次のようにawaitでInteractive Rebindingを待機しています。
キャンセルキーが押されるか、タイムアウトになると非同期処理はキャンセル扱いとなり、OperationCanceledExceptionがスローされるため、ここで決定かキャンセルかを判断しています。
処理が一通り終わったら、finallyブロックでマスク表示を消したり、CancellationTokenSourceを破棄したりしています。
CancellationTokenSource.CancelAfterメソッドを使ってタイムアウトを実装する場合、メインスレッド以外から実行されるため、Unityのゲームオブジェクトなどにアクセスする際は次のようにメインスレッドに戻す必要があります。
また、CancellationTokenSourceはIDisposableインタフェースを実装しているため、Disposeを忘れずに行う必要があります。
RebindingOperationクラスの拡張メソッドとして実装する
ここまで解説した方法は、InputActionクラスの拡張メソッドとして実装していました。
しかし、この方法ではRebindingOperationに対して次のように自由にメソッドチェイン出来ないといった欠点が存在します。
この場合、呼び元でAction無効化などの準備処理が増えますが、RebindingOperationに対する拡張メソッドとして実装すれば解決できます。
完成形の拡張メソッドは以下の通りです。
上記をRebindingOperationExtensions.csという名前でUnityプロジェクトに保存すれが拡張メソッドが使用可能になります。
使用例
以下、RebindingOperationの拡張メソッドを使用するように書き換えた例です。
使用方法は一つ目の使用例と一緒です。実行結果も一緒のため割愛します。
スクリプトの説明
主な相違点は以下部分です。
PerformInteractiveRebindingメソッドは、InputActionRebindingExtensionsクラスが提供する拡張メソッドです。
参考:Class InputActionRebindingExtensions| Input System | 1.6.3
PerformInteractiveRebindingメソッドを呼ぶときは、対象のInputActionが無効化されている必要があります。
Interactive Rebindingが完了したら、InputActionが無効化されたままなので、次の処理で有効化しています。
RebindingOperationインスタンスは最終的にDisposeメソッドで破棄する必要がありますが、これは独自実装したStartAsync拡張メソッド内で行うようにしたため不要です。
この辺は開発するアプリケーションや状況に応じて設計してください。
さいごに
Input Systemのキーコンフィグでユーザー入力を待機するInteractive Rebindingは、コールバックで結果を非同期的に受け取るものですが、これはUniTaskのasync/awaitに変換できます。
拡張メソッドを実装する必要がありますが、一度実装したら使いまわしが効いて便利になるでしょう。
CancellationTokenやInteractive Rebindingそのもののキャンセルにも対応できることも示しました。