

Input Systemで複数の入力デバイスに対応させたい場合はどうすればいいの?


Input Actionを使えばこの辺をスマートに管理できるわ。スクリプトからはどのデバイスかを意識せずに扱えるようになるの。
Input Systemでは、マウスやキーボード、ゲームパッドなどあらゆる入力デバイスを抽象的に扱えるようにするInput Actionが用意されています。
参考:Actions | Input System | 1.2.0
Input Actionを使うと、次のように入力デバイスに依存しないコードが書けるようになります。
private void OnMove(InputAction.CallbackContext context)
{
// 移動量取得
var moveInputValue = context.ReadValue<Vector2>();
}
private void OnJump(InputAction.CallbackContext context)
{
// ジャンプ処理
}
入力値は、独自に定義したActionという入力単位でアクセスして取得します。Actionとは操作の単位で、例えば次の操作を自分で定義して使うことができます。
- 移動する
- ジャンプする
- 攻撃する
本記事では、このようにデバイスに依存しない入力を扱えるようにするInput Actionの使い方について解説していきます。
最終的に以下動画のようにボールを操作するところを目標とします。
- Unity 2021.2.3f1
- Input System 1.1.1
前提条件
事前にInput Systemがインストールされ、有効化されているものとします。
ここまでの手順が終わっていない場合は、以下記事のインストール手順まで実施してください。
Input Actionの仕組み
Input Actionは、個別の入力デバイスへのアクセスを抽象化する役割を持ちます。
移動やジャンプ、攻撃などといった操作はActionという単位で管理します。


これらのActionは、Mapというグループ単位で管理されます。
スクリプトから操作入力を取得するときは、どのMapのどのActionかを指定する形でアクセスします。


Actionの中には、どの入力デバイスを参照するかといったキーバインド情報(Binding)が格納されます。


これにより、アクセス元のスクリプトはマウスやキーボードなどの入力を意識せずに扱うことができます。
Bindingには、入力デバイス情報のほかに、デッドゾーンや値の正規化など、値を加工する処理を設定することも可能です。


Input Systemを効果的に活用するにはInput Actionが不可欠だね。


そうね。次はInput Actionの具体的な使い方を見ていくね。
Input Actionsアセットの作成
オブジェクトの移動操作を例に、Input Actionを用いて入力を取得できるようにしていきます。
メニューのAssets > Create > Input Actionsの順に選択します。

すると、アセット名を入力できるようになるため、適当な名前を入力してInput Actionsアセットを作成します。例ではGameInputsとしました。

Actions Mapの作成
作成したInput Actionsアセットをダブルクリックすると、Input Actionsの編集ウィンドウが開きます。

左上のActions Maps右の+ボタンをクリックし、Action Map名を入力します。例ではPlayerとしました。

Map名および後述するAction名は重要です。本記事の終盤で紹介するサンプルスクリプトを動かすためには、必ず例の通りの名前に設定する必要があります。名前が違うとコンパイルエラーとなるためです。
Actionの作成
Action Mapの下にActionを作成していきます。例では、移動とジャンプのアクションをそれぞれMove、Jumpとして定義することとします。
初期状態では、New actionという名前のActionが1つ追加されている状態です。このActionをクリックすることで名前を変更できます。例では、Moveに変更することとします。

新しいActionの追加は、Actions右上の+ボタンから行います。

例ではJumpという名前のActionを一つ追加することとします。
Actionの定義
作成したActionの挙動を定義していきます。
例えば、移動操作なら2軸の入力値、ジャンプ操作ならボタンの押下状態を呼び元に渡す必要があります。
このようなActionの振る舞いは、Actionを選択した状態で表示されるAction Properties項目から設定します。

Action Propertiesには、次の設定項目があります。
- Action
- Actionの基本的な振る舞いを設定します。入力値の種類やスクリプトから扱う型などの設定があります。
- Interactions
- 長押しやダブルクリックなどの通知を設定します。
- Processors
- デッドゾーンや値の正規化、反転などの演算処理を設定します。
具体的な設定例を紹介します。
移動操作の設定例
ボールの移動は、WSADキーまたはゲームパッドの左スティックで行うものとします。
この場合、2軸の時系列で連続した値を返せば良いです。連続値を返すようにするには、Action > Action Type項目をValueに設定します。また、下に現れるAction > Control Type項目をVector2に設定します。
ジャンプ操作の設定例
ジャンプ操作はスペースキーまたはゲームパッドの下ボタン(South Button)で行うものとします。
この場合、Action > Action Type項目はButtonのままで良いです。

Bindingの定義
作成したActionにキーバインド情報を定義していきます。
Action名の左側にある三角アイコンをクリックし、Binding情報を表示します。

初期設定では、<No Binding>という未設定のBindingが存在しています。BindingはActionの右にある+アイコンから複数追加できます。

Bindingには入力デバイスのパスを定義するもののほか、WSAD入力や同時押しなど複数入力をまとめて管理するComposite Bindingsがあります。
Bindingに関する設定は、該当のBindingを選択した状態で右に表示されるBinding Properties項目から行います。

実際の設定例についても紹介します。
移動操作の設定例
ゲームパッドの左スティック入力は、Binding Properties > Binding > Path項目にGamepad > LeftStickを設定します。
パス選択リストの左上のListenボタンをクリックしてからコントローラー入力すると、該当するパスが即座に一覧出てくるので便利です。
WSADキーのBindingも併せて設定していきます。Action右の+アイコンからAdd Up\Down\Left\Right Compositeを選択します。
すると上下左右のBindingを内包したBindingが追加されます。
4方向それぞれに対して、先と同じ要領でBindingのパスを定義していきましょう。
ジャンプ操作の設定例
こちらも同じ要領でBindingを設定します。ゲームパッドとキーボードのBinding設定を行うものとします。
Input Actionsアセットの保存
ここまでの設定を行ったら、忘れずにSave Assetボタンをクリックして設定を保存します。

Input Actionsアセットを編集する度にこの操作が必要です。毎回の操作が面倒な場合は、Save Assetボタン右にあるAuto-Saveにチェックを入れておけば、変更が入る度に自動保存してくれるようになります。
移動とジャンプの実装例
ボールを移動させたりジャンプさせたりする例を紹介します。
次のようにシーン上に配置されたボールを操作できるようにしていきます。

Input Actionのソースコード生成
作成したInput Actionsアセットを選択し、Generate C# Classにチェックを入れます。
すると、保存するスクリプトファイル名(C# Class File)、クラス名(C# Class Name)、名前空間(C# Class Namespace)の設定項目が出現するため、必要に応じて設定し、Applyボタンをクリックします。

保存に成功すると、指定したパスにスクリプトが追加されます。

ボール操作スクリプトの実装
先述のInput Actionクラスから入力を取得し、ボールを操作するスクリプトを実装します。
以下スクリプトをPlayerMover.csという名前でUnityプロジェクトに保存します。
using System;
using UnityEngine;
using UnityEngine.InputSystem;
[RequireComponent(typeof(Rigidbody))]
public class PlayerMover : MonoBehaviour
{
[SerializeField] private float _moveForce = 5;
[SerializeField] private float _jumpForce = 5;
private Rigidbody _rigidbody;
private GameInputs _gameInputs;
private Vector2 _moveInputValue;
private void Awake()
{
_rigidbody = GetComponent<Rigidbody>();
// Actionスクリプトのインスタンス生成
_gameInputs = new GameInputs();
// Actionイベント登録
_gameInputs.Player.Move.started += OnMove;
_gameInputs.Player.Move.performed += OnMove;
_gameInputs.Player.Move.canceled += OnMove;
_gameInputs.Player.Jump.performed += OnJump;
// Input Actionを機能させるためには、
// 有効化する必要がある
_gameInputs.Enable();
}
private void OnDestroy()
{
// 自身でインスタンス化したActionクラスはIDisposableを実装しているので、
// 必ずDisposeする必要がある
_gameInputs?.Dispose();
}
private void OnMove(InputAction.CallbackContext context)
{
// Moveアクションの入力取得
_moveInputValue = context.ReadValue<Vector2>();
}
private void OnJump(InputAction.CallbackContext context)
{
// ジャンプする力を与える
_rigidbody.AddForce(Vector3.up * _jumpForce, ForceMode.Impulse);
}
private void FixedUpdate()
{
// 移動方向の力を与える
_rigidbody.AddForce(new Vector3(
_moveInputValue.x,
0,
_moveInputValue.y
) * _moveForce);
}
}
必要に応じてボールに与える力加減をインスペクターから調整します。

実行結果
スクリプトの解説
Input Actionの機能を参照するために、次の名前空間をusingします。
using UnityEngine.InputSystem;
そして、Input Actionの初期化を行います。
// Input Actionインスタンス生成
_gameInputs = new GameInputs();
// Actionイベント登録
_gameInputs.Player.Move.started += OnMove;
_gameInputs.Player.Move.performed += OnMove;
_gameInputs.Player.Move.canceled += OnMove;
_gameInputs.Player.Jump.performed += OnJump;
// Input Actionを機能させるためには、
// 有効化する必要がある
_gameInputs.Enable();
インスタンスを生成してから、各種Actionにイベントを登録しています。設定が終わったら、Enable()メソッドでInput Actionを動作させる必要があります。
Enable()メソッド呼び出しを忘れると、Input Actionが機能せず入力値が取得できなくなるためご注意ください。
各種Actionのコールバックは次のような形式になります。
private void OnMove(InputAction.CallbackContext context)
{
// Moveアクションの入力取得
_moveInputValue = context.ReadValue<Vector2>();
}
private void OnJump(InputAction.CallbackContext context)
{
// ジャンプする力を与える
_rigidbody.AddForce(Vector3.up * _jumpForce, ForceMode.Impulse);
}
引数contextのReadValue()メソッドから入力情報を取得できます。2つ目のジャンプイベントのほうは、ボタンが押された瞬間のみ呼び出されるため、力を与える処理のみ記述しています。
Input Systemは設定次第でUpdateやFixedUpdate、その他任意のタイミングで呼び出される可能性があります。そのため、OnMoveコールバック内では入力値の保存のみ行い、別途FixedUpdateイベントで参照する形をとっています。
さいごに
Input Actionを用いると、入力デバイスに依存しない実装が可能になります。
実装は、Input Actionの定義→入力取得するスクリプト作成という流れになります。
Input Action経由での入力取得は、Player Inputを通じて行うことができます。詳細は以下記事をご覧ください。