次のようにInput ActionのBindingをインスペクターから直接指定する方法はないの?
カスタムクラスを作ったりエディタ拡張を作ることになるけど可能だわ。
Input SystemのActionには、次のように複数のBindingが格納されます。
これらの各Bindingには、固有のGUIDが割当てられています。このGUIDをスクリプトで保持しておけば、Bindingへの参照を表現できます。
しかしながら、BindingのGUIDを毎回調べてインスペクターから指定するのは大変でしょう。
また、任意のスクリプトに対し、BindingのGUIDをインスペクターからGUIで選択して指定する手段はInput System 1.5.1現在では提供されていません。
そのため、エディタ拡張(Property Drawer)で設定用のUIを自作する必要が出てきます。
本記事では、このようなBinding参照を実現する自作クラスおよびエディタ拡張を実装して対応する方法を紹介します。
- Unity 2022.2.16f1
- Input System 1.5.1
目次 非表示
前提条件
事前にInput Systemパッケージがインストールされ、使用可能になっているものとします。
ここまでの手順がわからない方は、以下記事を参考にセットアップを進めてください。
また、本記事ではInput Actionを使用して入力を取得することを前提とします。
Input Actionの基本的な使い方は以下記事で解説しています。
本記事では、Input Action Asset内にあるBindingをスクリプトから参照可能にするものとして解説を進めます。
また、Bindingの参照およびエディタ拡張の実装は、Input Systemパッケージ公式のサンプル「Rebinding UI」のスクリプトRebindActionUI.csの内部実装を参考にしています。
参考:Class RebindActionUI| Input System | 1.0.2
クラスのソースコード
まず最初に、インスペクターからBindingへの参照指定を可能にし、スクリプトから楽に扱えるようにしたクラスの全体を示します。
クラス本体およびそのエディタ拡張(Property Drawer)が1つのファイルとなっています。
上記をInputBindingReference.csという名前でUnityプロジェクトに保存すると使用可能になります。
クラスの使い方
InputBindingReference型のフィールドをシリアライズ可能なフィールド([SerializeField]属性指定、publicなど)で定義すると機能するようになります。
以下、InputBindingReference型フィールドを定義し、その内容をログ出力する例です。
上記をUseExample.csという名前で保存し、Unityプロジェクトに保存し、適当なゲームオブジェクトにアタッチすると機能するようになります。
実行結果
次のようにインスペクターからInput Action AssetのBindingを指定できるようになります。
上記設定をした後にゲームを実行すると、コンソールにBindingへの参照情報がログ出力されます。
また、Bindingのキー(例ではスペースキー)を入力する度に文字列「performed!」がログ出力されます。
試しにDebugモードでインスペクターを表示してみると、BindingのGUIDが文字列としてシリアライズされていることが確認できます。
参考:Unity – Manual: Working in the Inspector
クラスの説明
上記で紹介したBindingへの参照を表すInputBindingReferenceクラスでは、内部的に次のフィールドを保持しています。
型 | フィールド名 | 説明 |
InputActionReference | _actionRef | InputActionAsset(ScriptableObject)のActionへの参照 |
string | _id | 参照先BindingのGUID文字列 |
InputActionReferenceはInput System側が提供しているクラスで、特定のActionへの参照を表すクラスです。
参考:Class InputActionReference| Input System | 1.5.1
また、関連情報へアクセスするための以下プロパティを公開しています。
型 | プロパティ名 | 説明 |
InputActionAsset | Asset | Bindingが属する大元のInput Action Assetインスタンス |
InputAction | Action | Bindingが属するActionインスタンス |
string | ID | BindingのGUID文字列 |
int | Index | Action中の自身のBindingのインデックス |
InputBinding | Binding | InputBindingインスタンス |
クラスの内部実装の説明
Input Action Assetの特定のBindingへの参照は、以下情報により決定できます。
- InputActionAsset(ScriptableObject)への参照(UnityEngine.ObjectのGUID)
- Bindingへの参照(GUID文字列)
ただし、本記事で紹介したクラスInputBindingReferenceでは、Action関連情報へのアクセスをしやすくするために、Actionの参照(GUID文字列)も追加で持たせるようにしています。
InputActionAssetとActionへの参照はInputActionReferenceで表現できるため、InputBindingReferenceクラスではInputActionReferenceインスタンスとBindingのGUIDを保持しておけば良いことになります。
これらのフィールドの内容に基づいて、各プロパティも機能するように実装しています。
GUIDからBindingを取得する処理は、次のインデックスを返すプロパティ内で行っています。
IndexOfメソッドを使ってGUIDが一致する要素を検索し、ヒットした要素のインデックスを返しています。
参考:Struct ReadOnlyArray<TValue>| Input System | 1.5.1
エディタ拡張部分の説明
エディタ拡張部分はInputBindingReferenceEditorクラスにより実装しています。InputBindingReferenceEditorクラスはPropertyDrawer継承クラスです。
Input Action AssetおよびActionへの参照は、InputActionReferenceクラスのPropertyDrawer側が実装してくれているため、次のようにプロパティを表示するだけで済みます。
指定されたActionのBindingを一覧表示するために、項目名の文字列配列を作成します。
最終的にbindingNames変数に各Bindingに対応した表示名が格納されます。配列のインデックスはBindingのインデックスに対応しています。
そして、以下でbindingNames変数の内容をドロップダウンリストで表示しています。
選択された項目に変更があったら、以下処理でBindingのGUIDを文字列に変換してInputBindingReferenceインスタンスの_idフィールドに反映します。
キーコンフィグでの活用例
本記事で紹介したInputBindingReferenceクラスは、例えばキーコンフィグの実装などで役立つかもしれません。
キーコンフィグでは、指定されたActionに対してリバインド(Bindingの上書き)を行いますが、この時どのBindingかをインデックスで指定する必要があります。
本記事のクラスを使うと、インスペクターから指定したBindingのインデックスを簡単に取得できるようになります。
キーコンフィグでどのBindingを使用するかの指定は、他にもスキームなどで条件を絞ったりして決定することもできます。
方法の一つとして検討していただければ幸いです。
Input Systemパッケージのサンプル「Rebinding UI」にあるスクリプトRebindActionUI.csでも同様の実装例がありますが、本記事で紹介したInputBindingReferenceクラスはどのスクリプトでも簡単に使いまわせる利点があります。
使用上の注意事項
当記事で紹介したクラスはBindingの指定を楽にする一方、注意すべき点も存在します。
Input Action AssetのBindingを削除した時
InputBindingReferenceクラスから参照しているBindingが削除されると、存在しないBindingのGUIDを保持することになり、Missingとなります。
インスペクター上では何も選択されない状態になります。
例えばBindingを作り直したりした時などは、GUIDが変わるためインスペクターからもう一度指定し直す必要があります。
Input Action AssetのBinding内容を変更した時
クラスからは内部的にInputActionAsset(ScriptableObject)をインスタンス化し、この中のBinding情報にアクセスするようになっています。
そのため、Input Action Asset側のBindingの内容(Control Pathなど)を変更した場合は、再度リフレッシュするまで古い表示のままになっています。
この場合、ドメインリロードを有効化した状態でプレイ するか、Unityを再起動すれば改善されます。
特に、起動高速化のためにドメインリロードが無効化されている場合は注意が必要です。
参考:Unity – Manual: Domain Reloading
さいごに
本記事で紹介したInputBindingReferenceクラスは、Bindingへの参照情報の管理およびインスペクターからのBinding設定を簡単に行える利点があります。
また、スクリプトでフィールドを定義するだけで機能するので扱いも楽になるでしょう。