「キーボードでもゲームパッドでも操作できるようにしたい」「プレイヤーがキー配置を変更できるようにしたい」――こんな要望を実現しようとして、旧Input Systemで苦労した経験はありませんか?
New Input System は、Unity 2019から導入された次世代の入力処理システムです。 Input Actions という抽象化された概念を使って、デバイスに依存しない柔軟な入力処理を実現します。
この記事でわかること
- Input Actionsの仕組み(デバイス非依存の入力処理)
- Input Actions Assetの作成からスクリプト実装までの流れ
- Player Input方式とC# Class生成方式の使い分け
- 「移動が止まらない」などの定番トラブルの解決方法
動作確認環境: Unity 2022.3 LTS / Unity 6
インストールと初期設定
パッケージのインストール
Window > Package Managerを開く- 左上のドロップダウンから
Unity Registryを選択 Input Systemを検索してインストール- 再起動を促すダイアログが表示されたら「Yes」をクリック
Active Input Handlingの設定
Edit > Project Settings > Playerを開くOther Settings > Configuration > Active Input Handlingを確認- Both または Input System Package (New) を選択
- エディタが再起動される
Both: 旧Input Systemと新Input Systemの両方が使用可能。移行期間中に便利です。
旧Input Systemとの違い
旧Input Systemの問題点
- デバイスごとに個別のコードが必要
- キーバインドのカスタマイズが困難
- マルチプラットフォーム対応が大変
- ローカルマルチプレイヤー対応が困難
New Input Systemの利点
- デバイス非依存の実装 - 同じコードで複数デバイスに対応
- マルチプラットフォーム対応 - 設定ファイルで一元管理
- キーバインドのカスタマイズ - 標準機能として提供
- ローカルマルチプレイヤー対応 - Player Inputコンポーネントで簡単に実装
- 複雑な入力パターン - 長押し、ダブルクリックなどを設定だけで実現
新旧の構造の違いを図にすると、New Input Systemの狙いがよく分かります。デバイスごとにバラバラだった入力処理が、「Action」という1つの窓口に集約されるのです。

New Input Systemの構成要素
| 要素 | 説明 |
|---|---|
| Input Actions Asset | 入力設定を保存するファイル |
| Action Map | 関連するActionをグループ化したもの |
| Action | 操作の単位(移動、ジャンプなど) |
| Binding | Actionと実際の入力デバイスを結びつけるもの |
| Player Input | 入力イベントを受け取るコンポーネント |

Action Type
| タイプ | 用途 |
|---|---|
| Value | 連続的な値(移動スティック、トリガーなど) |
| Button | ボタンの押下状態(ジャンプ、攻撃など) |
| Pass-through | 入力をそのまま伝える(複数入力点の処理) |
Input Actionsの作成と設定
Input Actions Assetの作成
- Projectウィンドウで右クリック
Create > Input Actionsを選択- アセットをダブルクリックして編集ウィンドウを開く
Action Mapの作成
左上の+ボタンをクリックして、新しいAction Mapを追加(例:「Player」)
Actionの作成
- Action Mapを選択した状態 で
+ボタンをクリック - Action名を入力(例:「Move」「Jump」)
- Action TypeとControl Typeを設定
Bindingの追加
WASDキーの設定例:
- 「Move」Actionを選択
+ボタンからAdd Up/Down/Left/Right Compositeを選択- Up: W、Down: S、Left: A、Right: Dを設定
ゲームパッド左スティックの追加:
- 同じ「Move」Actionを選択
+ボタンからAdd Bindingを選択- Pathで
Gamepad > Left Stickを選択
マルチデバイス対応: 同じActionに複数のBindingを追加することで、キーボードでもゲームパッドでも同じコードで動作します。
C# Classの生成(推奨)
Input Actions Assetからタイプセーフなクラスを自動生成できます。
そもそも「タイプセーフ」とは?: 「型(タイプ)によって安全が守られている」という意味です。Actionを
"Move"のような 文字列 で指定する書き方だと、"Mvoe"とタイプミスしてもコンパイルは通ってしまい、実行して動かなくなって初めてミスに気づきます。一方、生成したクラスを使えばinputActions.Player.Moveのように コードの一部 として書けるため、ミスした瞬間にエディタがエラーで教えてくれて、入力補完(インテリセンス)も効きます。これが「タイプセーフ」の恩恵です。

- ProjectウィンドウでInput Actions Assetを選択
- Inspectorで Generate C# Class にチェック
- Class Name(例:
PlayerInputActions)を設定 - 必要に応じてNamespaceを設定
- Apply をクリック
これにより、PlayerInputActions.csが生成され、new PlayerInputActions()でインスタンス化できるようになります。
スクリプトでの実装
方法の使い分け
| 方法 | 適したケース |
|---|---|
| Player Input + Unity Events | 小規模プロジェクト、プロトタイプ、プログラマー以外も設定を変更する場合 |
| C# Class生成 | 中〜大規模プロジェクト、タイプセーフな実装が必要な場合、複雑な入力処理 |
注意(二重有効化):
Player Inputコンポーネント方式と、生成C#クラスをnewする方式を、 同じActionアセットで併用しない でください。同じActionが二重に有効化されてコールバックが2回ずつ飛び、「入力が2連発する」バグの定番原因になります。プロジェクト内でどちらか一方に統一しましょう。
方法1: Player Input + Unity Events
Player Inputコンポーネントを使うと、インスペクターでActionとメソッドを紐づけることが できます。
Player Inputコンポーネントの設定
- GameObjectに
Player Inputコンポーネントを追加 ActionsにInput Actions Assetを設定Behaviorを Unity Events に変更Eventsセクションが表示される- 各Actionに対応するメソッドを登録
using UnityEngine;
using UnityEngine.InputSystem;
public class PlayerController : MonoBehaviour
{
private Vector2 moveInput;
public void OnMove(InputAction.CallbackContext context)
{
moveInput = context.ReadValue<Vector2>();
}
public void OnJump(InputAction.CallbackContext context)
{
if (context.performed)
{
Debug.Log("ジャンプ!");
}
}
}
方法2: C# Class生成(推奨)
この方法のコードには+=という見慣れない記号が登場します。これは イベント登録(購読) と呼ばれる仕組みで、「このActionが発生したら、私のこのメソッドを呼んでください」とあらかじめ申し込んでおくイメージです。一度登録すれば、あとは入力が発生するたびにUnity側から自動でメソッドが呼ばれます。逆に-=は「もう呼ばなくていいです」という登録の解除です。

using UnityEngine;
using UnityEngine.InputSystem;
public class PlayerController : MonoBehaviour
{
private PlayerInputActions inputActions;
private Vector2 moveInput;
void Awake()
{
inputActions = new PlayerInputActions();
inputActions.Player.Move.performed += OnMove;
inputActions.Player.Move.canceled += OnMove;
inputActions.Player.Jump.performed += OnJump;
}
void OnEnable() => inputActions.Enable();
void OnDisable() => inputActions.Disable();
void OnDestroy()
{
// イベントハンドラの解除(メモリリーク防止)
inputActions.Player.Move.performed -= OnMove;
inputActions.Player.Move.canceled -= OnMove;
inputActions.Player.Jump.performed -= OnJump;
inputActions.Dispose();
}
private void OnMove(InputAction.CallbackContext context)
{
moveInput = context.ReadValue<Vector2>();
}
private void OnJump(InputAction.CallbackContext context)
{
Debug.Log("ジャンプ!");
}
}
メモリリーク防止:
OnDestroyでイベントハンドラを-=で解除し、Dispose()を呼び出すことで、オブジェクト破棄時のメモリリークを防げます。
ところで、なぜMoveにはperformedとcanceledの 両方 に登録しているのでしょうか。Actionのイベントには主にstarted(入力が始まった)・performed(入力が成立した)・canceled(入力が終わった)の3つのタイミングがあります。移動のように「押している間ずっと値が欲しい」操作では、performedだけだと スティックを離しても最後の値が残って動き続けて しまいます。canceledにも登録しておくと、離した瞬間にVector2.zeroが届いてピタッと止まれるのです。

Action Mapの切り替え
ゲームプレイ中とUI操作中で、有効なAction Mapを切り替えることができます。
public class InputManager : MonoBehaviour
{
private PlayerInputActions inputActions;
void Awake()
{
inputActions = new PlayerInputActions();
}
// ゲームプレイ中:PlayerマップをON、UIマップをOFF
public void EnableGameplayInput()
{
inputActions.Player.Enable();
inputActions.UI.Disable();
}
// UI操作中:UIマップをON、PlayerマップをOFF
public void EnableUIInput()
{
inputActions.Player.Disable();
inputActions.UI.Enable();
}
}
活用例: ポーズメニューを開いたらUIマップに切り替え、閉じたらPlayerマップに戻す。これにより、メニュー操作中にキャラクターが動くことを防げます。
InteractionsとProcessors
Interactions
| Interaction | 用途 |
|---|---|
| Hold | 長押しで発火 |
| Tap | 短いタップを検知 |
| Multi Tap | ダブルクリックなどの連続タップを検知 |
Processors
| Processor | 用途 |
|---|---|
| Normalize | ベクトルを正規化(斜め移動の速度補正) |
| Invert | 入力値を反転 |
| Scale | 入力値をスケーリング(感度調整) |
| Dead Zone | スティックのわずかな傾きを無視 |
デバイスの接続/切断検知
ゲ ームパッドの抜き差しなど、デバイスの状態変化を検知できます。
using UnityEngine;
using UnityEngine.InputSystem;
public class DeviceManager : MonoBehaviour
{
void OnEnable()
{
InputSystem.onDeviceChange += OnDeviceChange;
}
void OnDisable()
{
InputSystem.onDeviceChange -= OnDeviceChange;
}
void OnDeviceChange(InputDevice device, InputDeviceChange change)
{
switch (change)
{
case InputDeviceChange.Added:
Debug.Log($"デバイス接続: {device.displayName}");
break;
case InputDeviceChange.Removed:
Debug.Log($"デバイス切断: {device.displayName}");
break;
}
}
}
活用例: ゲームパッドが切断されたらポーズ画面を表示する、接続されたら「コントローラーを検出しました」と通知するなど。
実践:1人のプレイヤーを最後まで組む
部品の説明はそろいました。ここからは、3Dアクションの主人公、2Dプラットフォーマーの自機、見下ろしARPGの操作キャラ——どのジャンルでも必要になる 「1人のプレイヤー入力一式」 を1本のスクリプトに組み上げます。内容は、①移動+ジャンプ、②ポーズでPlayer⇄UIのMap切替、③ゲームパッドが抜かれたら自動ポーズ、の3点セットです。

Input Actions側の準備: PlayerマップにMove(Vector2)・Jump(Button)・Pause(Button、Escキーとパッドのメニューボタン)、UIマップにResume(Button)を作り、C# Classを生成しておきます。
using UnityEngine;
using UnityEngine.InputSystem;
[RequireComponent(typeof(CharacterController))]
public class OnePlayerController : MonoBehaviour
{
[SerializeField] private float moveSpeed = 5f;
[SerializeField] private GameObject pausePanel; // ポーズ画面のUI
private PlayerInputActions input;
private CharacterController controller;
private Vector2 moveInput;
void Awake()
{
controller = GetComponent<CharacterController>();
input = new PlayerInputActions();
// 購読はAwakeで登録し、OnDestroyで解除(対で管理する)
input.Player.Move.performed += OnMove;
input.Player.Move.canceled += OnMove;
input.Player.Jump.performed += OnJump;
input.Player.Pause.performed += OnPause;
input.UI.Resume.performed += OnResume;
}
void OnEnable()
{
// 有効化はOnEnable/OnDisableで対にする
input.Player.Enable();
InputSystem.onDeviceChange += OnDeviceChange;
}
void OnDisable()
{
input.Disable();
InputSystem.onDeviceChange -= OnDeviceChange;
}
void OnDestroy()
{
input.Player.Move.performed -= OnMove;
input.Player.Move.canceled -= OnMove;
input.Player.Jump.performed -= OnJump;
input.Player.Pause.performed -= OnPause;
input.UI.Resume.performed -= OnResume;
input.Dispose();
}
void Update()
{
// 移動(簡易版。カメラ基準にしたい場合はCharacterControllerの記事参照)
Vector3 move = new Vector3(moveInput.x, 0f, moveInput.y);
controller.SimpleMove(move * moveSpeed);
}
private void OnMove(InputAction.CallbackContext ctx) => moveInput = ctx.ReadValue<Vector2>();
private void OnJump(InputAction.CallbackContext ctx) => Debug.Log("ジャンプ!");
private void OnPause(InputAction.CallbackContext ctx) => OpenPause();
private void OnResume(InputAction.CallbackContext ctx) => ClosePause();
private void OpenPause()
{
pausePanel.SetActive(true);
input.Player.Disable(); // 操作の主導権をUIマップへ
input.UI.Enable();
Time.timeScale = 0f;
}
private void ClosePause()
{
pausePanel.SetActive(false);
input.UI.Disable();
input.Player.Enable();
Time.timeScale = 1f;
}
private void OnDeviceChange(InputDevice device, InputDeviceChange change)
{
// ゲームパッドが抜かれた瞬間に自動ポーズ(操作不能の棒立ちで死ぬのを防ぐ)
if (device is Gamepad && change == InputDeviceChange.Removed && !pausePanel.activeSelf)
{
OpenPause();
}
}
}
再生して確認してみてください。WASD/左スティックで移動、Spaceでジャンプ、Escでポーズが開いて キャラが動かなくなり(Playerマップが無効)、Resumeで戻る。そしてプレイ中にゲームパッドのUSBを抜くと、その瞬間にポーズ画面が開きます——市販ゲームで見るあの挙動です。
ポイントは2つです。 「購読はAwake/OnDestroy、 有効化はOnEnable/OnDisableで、それぞれ対にする」(登録しっぱなし・有効化しっぱなしを構造で防ぐ)と、 「Map切替をポーズの開閉と1対1で結びつける」(Time.timeScaleだけのポーズは入力が素通りします。Mapごと切り替えるから「ポーズ中に攻撃が暴発」しない。ポーズの全体像は ポーズ実装の記事 参照)。
よくある問題とトラブルシューティング
入力が反応しない
OnEnableでinputActions.Enable()を呼び出しているか確認- Action Mapが有効になっているか確認
- Bindingが正しく設定されているか確認
- ビルドに含まれていない場合: Input Actions Assetの設定を確認(下記参照)
Input Actions Assetがビルドに含まれない
Input Actions Assetをビルドに含めるには、以下のいずれかの方法を使用します:
- Player Inputコンポーネントで参照する - GameObjectにアタッチしたPlayer Inputコンポーネントで参照
- スクリプトから参照する -
[SerializeField]でアセットを参照 - Addressablesに登録する - Addressable Assetとして管理
注意: Input System 1.1以前にあった「Preload」チェックボックスは廃止されています(Unity 2021以降)。上記の方法でアセットを参照してください。
移動が止まらない
canceledイベントも登録する:
inputActions.Player.Move.performed += OnMove;
inputActions.Player.Move.canceled += OnMove;
なぜ同じメソッドでいい?:
canceledイベント発火時、context.ReadValue<Vector2>()は自動的にVector2.zeroを返します。そのため、performedとcanceledで同じOnMoveメソッドを使用しても、入力がないときは正しくVector2.zeroが設定されます。
斜め移動が速い
- Composite BindingのModeを「Digital Normalized」に設定
- または「Normalize Vector 2」Processorを追加
おまけ:先に知っておくと良いこと
New Input Systemに慣れてきたら、次はこのあたりが視野に入ってきます。
- キーコンフィグ(リバインド)の実装: プレイヤーが自分でキー配置を変更できる機能は、
PerformInteractiveRebinding()というAPIで実現できます。New Input Systemを選ぶ大きな理由のひとつです。 - 旧Input Systemの知識も無駄にならない: 既存プロジェクトやアセットストアのコードでは旧
Inputクラスがまだまだ現役です。旧Input Systemの記事 で両方を知っておくと移行やデバッグに強くなります。 - 入力を読むタイミングの理解: 入力の検知とキャラクター移動の実装には、
UpdateとFixedUpdateの使い分けの理解が欠かせません。Update vs FixedUpdateの記事 を合わせて読むのがおすすめです。 - 公式ドキュメントも頼れる情報源: InteractionsやProcessorsの全種類など、細かい仕様は Unity公式のInput Systemドキュメント が最も正確です。
まとめ
New Input Systemは、学習コストが高いものの、それに見合う強力な機能を提供します。
- Input Actions でデバイス非依存の入力処理
- Action Map で状況に応じた入力切り替え
- Binding で複数デバイスに同じActionを割り当て
- InteractionsとProcessors で複雑な入力パターンを設定だけで実現
- C# Class生成 でタイプセーフな実装
まずは簡単な移動とジャンプから始めて、徐々に複雑な機能に挑戦してみてください。