unity-input について
unity-input は、Unity 開発者向けに Input System のアクションベースの設定と入力取得を解説するガイドです。旧 Input Manager との違いを踏まえ、複数デバイス、ローカルマルチプレイヤー、タッチ、実行時の再バインドを扱います。
主な機能
- 01InputAction と Action Map
- 02PlayerInput によるローカルマルチプレイヤー管理
- 03ポーリングとイベント駆動の入力取得
- 04キーボード、ゲームパッド、マウス、タッチ
- 05入力インタラクションとプロセッサー
- 06実行時の再バインドとデバイス検出
活用シーン
- 01複数デバイスに対応する操作設定
- 02ゲームプレイと UI の Action Map 切り替え
- 03ローカルマルチプレイヤーのデバイス割り当て
- 04実行時の操作再バインドの追加
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ nice-wolf-studio/ unity-claude-skills --skill unity-inputインストール後、Claude Code で/unity-inputを入力して読み込まれたか確認します。
同梱ファイルreferences/input-system-api.md
詳細
Unity Input System
Input System の概要:新旧の比較
Unity には、2 つの入力システムがあります。
| 機能 | 新しい Input System(推奨) | レガシー Input Manager |
|---|---|---|
| パッケージ | com.unity.inputsystem(Unity 6.3 向け v1.19.0) | 組み込み(UnityEngine.Input) |
| アーキテクチャ | アクションベース、イベント駆動 | ポーリングベース |
| デバイスのサポート | ゲームパッド、キーボード、マウス、タッチ、XR、カスタム | キーボード、マウス、ジョイスティック |
| マルチプレイヤー | PlayerInput によるローカルマルチプレイヤー機能を内蔵 | 手動で実装 |
| 再バインド | 実行時の再バインドに対応 | 非対応 |
| クロスプラットフォーム | デバイスタイプごとのコントロールスキーム | プラットフォームごとに手動でコードを作成 |
新しい Input System は、Package Manager からインストールするパッケージです。従来の Input.GetKey/Input.GetAxis API を、入力の目的とデバイスのコントロールを分離するアクションベースのモデルに置き換えます。
名前空間: UnityEngine.InputSystem
クイックスタートの設定
1. パッケージをインストールする
Window > Package Manager > Unity Registry > Input System からインストールします。
2. プロジェクト全体で使用するデフォルトのアクションを作成する
Edit > Project Settings > Input System Package > Input Actions に移動し、「Create and assign a default project-wide Action Asset」 をクリックします。
次のデフォルトのアクションマップが作成されます。
- Player:Move、Look、Jump、Attack
- UI:Navigate、Submit、Cancel
各アクションには、キーボード、ゲームパッド、XR コントローラー、タッチスクリーン向けのバインディングが含まれています。
3. スクリプトで入力を読み取る
using UnityEngine;
using UnityEngine.InputSystem;
public class PlayerController : MonoBehaviour
{
InputAction moveAction;
InputAction jumpAction;
void Start()
{
moveAction = InputSystem.actions.FindAction("Move");
jumpAction = InputSystem.actions.FindAction("Jump");
}
void Update()
{
Vector2 moveValue = moveAction.ReadValue<Vector2>();
transform.Translate(new Vector3(moveValue.x, 0, moveValue.y) * Time.deltaTime * 5f);
if (jumpAction.IsPressed())
{
// Jump logic
}
}
}
複数のマップで同じ名前のアクションを使用する場合は、"Player/Move" のように両方を指定します。
Input Actions と Action Maps
基本概念
- InputAction:コントロール値を返す、またはコールバックを呼び出す名前付きアクション
- InputActionMap:関連するアクション(「Player」、「UI」、「Vehicle」など)をまとめた名前付きコレクション
- InputBinding:アクションとデバイスコントロールの関係
- InputSystem.actions:プロジェクト全体で使用するアクションへの参照
アクションの作成
方法 1 — Input Actions Editor(推奨): Project Settings > Input System Package から設定します。
方法 2 — MonoBehaviour のフィールド: スクリプトで InputAction フィールドを直接宣言します(Inspector で設定可能)。
方法 3 — コード:
var moveAction = new InputAction("Move", InputActionType.Value);
moveAction.AddCompositeBinding("Dpad")
.With("Up", "<Keyboard>/w").With("Down", "<Keyboard>/s")
.With("Left", "<Keyboard>/a").With("Right", "<Keyboard>/d");
moveAction.Enable();
方法 4 — JSON: var map = InputActionMap.FromJson(jsonString);
アクションのライフサイクル
アクションは無効の状態で開始します。入力に応答させるには、.Enable() を呼び出す必要があります。有効な状態ではバインディングを変更できないため、先に .Disable() を呼び出してください。
Input Action アセット(.inputactions)
アクション、バインディング、コントロールスキームを保存する JSON ファイルです。Assets > Create > Input Actions から作成します。
C# クラスの自動生成: アセットのインポーターで「Generate C# Class」を有効にすると、型安全にアクセスできます。
public class MyPlayerScript : MonoBehaviour, IGameplayActions
{
MyPlayerControls controls;
public void OnEnable()
{
controls = new MyPlayerControls();
controls.gameplay.SetCallbacks(this);
controls.gameplay.Enable();
}
public void OnDisable()
{
controls.gameplay.Disable();
}
public void OnMove(InputAction.CallbackContext context)
{
Vector2 move = context.ReadValue<Vector2>();
// Handle movement
}
}
PlayerInput コンポーネント
PlayerInput コンポーネントは Input Actions をスクリプトのメソッドにマッピングし、デバイスフィルタリングと画面分割によるローカルマルチプレイヤーを処理します。
設定
- プレイヤーの GameObject に
PlayerInputコンポーネントを追加します - Actions フィールドに Action Asset を割り当てます
- Default Action Map を選択します
- 通知タイプの Behavior を選択します
Behavior のオプション
| Behavior | 仕組み | 適した用途 |
|---|---|---|
| Send Messages | GameObject.SendMessage() | 簡単なプロトタイピング |
| Broadcast Messages | 階層内に BroadcastMessage() を送信 | コンポーネント階層 |
| Invoke Unity Events | Inspector で設定するイベントルーティング | デザイナー向けの接続 |
| Invoke C# Events | onActionTriggered、onDeviceLost、onDeviceRegained | プログラマーによる制御 |
Send Messages パターン
public class PlayerActions : MonoBehaviour
{
public void OnJump()
{
// Called when Jump action triggers (no parameters)
}
public void OnMove(InputValue value)
{
Vector2 v = value.Get<Vector2>();
// InputValue is only valid during this callback
}
}
Unity Events パターン
public void OnFire(InputAction.CallbackContext context)
{
if (context.performed)
{
// Fire logic
}
}
PlayerInput の管理
PlayerInput playerInput = GetComponent<PlayerInput>();
playerInput.DeactivateInput(); // Disable all input
playerInput.ActivateInput(); // Re-enable with default map
playerInput.SwitchCurrentActionMap("Vehicle"); // Switch action map
コードで入力を読み取る
ポーリング(Update 内)
// 2D movement axis
Vector2 move = moveAction.ReadValue<Vector2>();
// Button state
if (jumpAction.IsPressed()) { /* held down */ }
if (jumpAction.WasPressedThisFrame()) { /* just pressed */ }
if (jumpAction.WasReleasedThisFrame()) { /* just released */ }
コールバック(イベント駆動)
void OnEnable()
{
fireAction.started += OnFireStarted;
fireAction.performed += OnFirePerformed;
fireAction.canceled += OnFireCanceled;
fireAction.Enable();
}
void OnDisable()
{
fireAction.started -= OnFireStarted;
fireAction.performed -= OnFirePerformed;
fireAction.canceled -= OnFireCanceled;
fireAction.Disable();
}
void OnFireStarted(InputAction.CallbackContext ctx) { /* Input began */ }
void OnFirePerformed(InputAction.CallbackContext ctx) { /* Completed */ }
void OnFireCanceled(InputAction.CallbackContext ctx) { /* Interrupted */ }
ゲームパッド/キーボード/マウス/タッチ
ゲームパッド
using UnityEngine.InputSystem;
// Current gamepad (null if none connected)
var gp = Gamepad.current;
if (gp == null) return;
Vector2 leftStick = gp.leftStick.ReadValue();
bool southPressed = gp.buttonSouth.isPressed;
// Access by enum
gp[GamepadButton.LeftShoulder].isPressed;
gp[GamepadButton.Y].isPressed; // Xbox style
gp[GamepadButton.Triangle].isPressed; // PlayStation style
// Rumble / Haptics
gp.SetMotorSpeeds(0.25f, 0.75f); // low-frequency, high-frequency
gp.ResetHaptics();
// Global haptics control
InputSystem.PauseHaptics();
InputSystem.ResumeHaptics();
InputSystem.ResetHaptics();
対応するゲームパッド:DualShock 3/4、DualSense、Xbox(XInput/Bluetooth)、Switch Pro。汎用 HID ゲームパッドは Gamepad デバイスではなく、汎用ジョイスティックとして認識されます。
キーボードとマウス
var kb = Keyboard.current;
if (kb.spaceKey.wasPressedThisFrame) { /* space pressed */ }
var mouse = Mouse.current;
Vector2 mousePos = mouse.position.ReadValue();
float scroll = mouse.scroll.ReadValue().y;
bool leftClick = mouse.leftButton.isPressed;
タッチ
API レベルは 2 つあります。
低レベル — タッチスクリーンデバイス:
var ts = Touchscreen.current;
if (ts.primaryTouch.press.isPressed)
{
Vector2 pos = ts.primaryTouch.position.ReadValue();
}
高レベル — EnhancedTouch API:
using UnityEngine.InputSystem.EnhancedTouch;
void OnEnable() => EnhancedTouchSupport.Enable();
void OnDisable() => EnhancedTouchSupport.Disable();
void Update()
{
foreach (var touch in Touch.activeTouches)
{
Debug.Log($"{touch.touchId}: {touch.screenPosition}, {touch.phase}");
}
}
タッチフェーズ:Began、Moved、Stationary、Ended、Cancelled。
Actions によるマルチタッチ: <Touchscreen>/touch*/press をバインドし、アクションタイプを PassThrough に設定すると、タッチごとのコールバックを受け取れます。
タッチシミュレーション: 開発中にマウス/ペンからのタッチをシミュレートするには、TouchSimulation.Enable() で有効にします。
デバイスの検出
// Monitor device connections
InputSystem.onDeviceChange += (device, change) =>
{
if (change == InputDeviceChange.Added)
Debug.Log($"Device connected: {device.displayName}");
};
インタラクションとプロセッサー
インタラクションは、アクションフェーズを駆動する入力パターンを定義します。
インタラクションフェーズ
| フェーズ | 意味 |
|---|---|
| Waiting | 入力待ち |
| Started | 入力を受け取りましたが、まだ完了していません |
| Performed | インタラクションが完了しました — 主な応答のトリガー |
| Canceled | インタラクションが中断されました |
組み込みインタラクション
| インタラクション | 説明 | 主なパラメーター |
|---|---|---|
| Default | 自動適用されます。動作はアクションタイプによって異なります | — |
| Press | 明示的なボタン押下の動作 | pressPoint、behavior(PressOnly/ReleaseOnly/PressAndRelease) |
| Hold | 最小時間にわたって押し続けます | duration、pressPoint |
| Tap | 素早く押して離します | duration、pressPoint |
| SlowTap | 押し続けてから離します | duration、pressPoint |
| MultiTap | タップを繰り返すシーケンス | tapTime、tapDelay、tapCount、pressPoint |
コードでインタラクションを追加する
var action = new InputAction("fire");
action.AddBinding("<Gamepad>/buttonSouth")
.WithInteractions("tap(duration=0.8)");
タップと長押しの例(発射とチャージ)
var fireAction = new InputAction("fire");
fireAction.AddBinding("<Gamepad>/buttonSouth").WithInteractions("tap,slowTap");
fireAction.started += ctx => { if (ctx.interaction is SlowTapInteraction) ShowChargingUI(); };
fireAction.performed += ctx => {
if (ctx.interaction is SlowTapInteraction) ChargedFire(); else Fire();
};
fireAction.canceled += _ => HideChargingUI();
fireAction.Enable();
カスタムインタラクション
IInputInteraction を実装し、InputSystem.RegisterInteraction<T>() で登録します。完全な例については、references/input-system-api.md を参照してください。
よくあるパターン
アクションマップの切り替え(例:ゲームプレイと UI)
public class GameStateManager : MonoBehaviour
{
PlayerInput playerInput;
void Start() => playerInput = GetComponent<PlayerInput>();
public void EnterMenu() => playerInput.SwitchCurrentActionMap("UI");
public void ExitMenu() => playerInput.SwitchCurrentActionMap("Player");
}
実行時の再バインド
var rebindOp = action.PerformInteractiveRebinding()
.WithControlsExcluding("Mouse")
.OnMatchWaitForAnother(0.1f)
.OnComplete(op =>
{
Debug.Log($"Rebound to: {op.action.bindings[0].effectivePath}");
op.Dispose();
})
.Start();
同じアクションに複数のバインディングを設定する(WASD + 矢印キー)
var moveAction = new InputAction("Move", InputActionType.Value);
moveAction.AddCompositeBinding("2DVector")
.With("Up", "<Keyboard>/w").With("Down", "<Keyboard>/s")
.With("Left", "<Keyboard>/a").With("Right", "<Keyboard>/d");
moveAction.AddCompositeBinding("2DVector")
.With("Up", "<Keyboard>/upArrow").With("Down", "<Keyboard>/downArrow")
.With("Left", "<Keyboard>/leftArrow").With("Right", "<Keyboard>/rightArrow");
アンチパターン
| アンチパターン | 問題 | 正しい方法 |
|---|---|---|
Input.GetKey()(旧式)を使用する | 新しい Input System と互換性がなく、再バインドや複数デバイスに対応できません | バインディングを設定した InputAction を使用します |
.Enable() を呼び出さずにアクションを読み取る | アクションは無効な状態で開始するため、値を返しません | OnEnable() で必ず action.Enable() を呼び出します |
クリーンアップ時に .Disable() を忘れる | メモリリークや予期しないコールバックが発生します | OnDisable() で action.Disable() を呼び出します |
| アクションが有効な状態でバインディングを変更する | 例外がスローされます | 変更前に .Disable() を呼び出し、その後 .Enable() を呼び出します |
| ゲームプレイコードにデバイスパスをハードコードする | クロスプラットフォーム対応が損なわれます | 代わりに Actions + Control Schemes を使用します |
コールバックの外で InputValue を使用する | 値が有効なのはコールバックのフレーム中のみです | 値をすぐにフィールドへコピーします |
null チェックなしで Gamepad.current にアクセスする | ゲームパッドが接続されていない場合、クラッシュします | 必ず if (Gamepad.current == null) return; で確認します |
| アクションのコールバックを登録解除しない | シーンの再読み込み時にエラーが発生します | OnDisable() で登録を解除します |
本番環境で SendMessages の動作を使用する | リフレクションによるパフォーマンス上のオーバーヘッドが発生します | Invoke Unity Events または Invoke C# Events を使用します |
EnhancedTouch を有効にせずにポーリングする | 空のコレクションが返されます | 先に EnhancedTouchSupport.Enable() を呼び出します |
主要な API クイックリファレンス
| API | 用途 |
|---|---|
InputSystem.actions | プロジェクト全体のアクション |
InputSystem.actions.FindAction("name") | 名前でアクションを検索 |
action.ReadValue<T>() | 現在の値を読み取る |
action.IsPressed() | ボタンが押されているか確認 |
action.WasPressedThisFrame() | ボタンがこのフレームで押されたか確認 |
action.WasReleasedThisFrame() | ボタンがこのフレームで離されたか確認 |
action.Enable() / action.Disable() | 有効化/無効化 |
action.started / performed / canceled | コールバックイベント |
action.AddBinding("path") | コードでバインディングを追加 |
action.AddCompositeBinding("type") | コンポジット(Dpad、2DVector)を追加 |
.WithInteractions("tap(duration=0.5)") | バインディングにインタラクションを追加 |
Gamepad.current | 現在のゲームパッドへの参照 |
Keyboard.current / Mouse.current | 現在のキーボード/マウス |
Touchscreen.current | 現在のタッチスクリーン |
EnhancedTouchSupport.Enable() | 拡張タッチ API を有効化 |
Touch.activeTouches | すべてのアクティブなタッチ(拡張) |
InputSystem.onDeviceChange | デバイス接続イベント |
PlayerInput.SwitchCurrentActionMap() | アクティブなアクションマップを変更 |
action.PerformInteractiveRebinding() | 実行時のリバインドを開始 |
関連するスキル
- unity-scripting — MonoBehaviour のライフサイクル、C# のパターン
- unity-ui — UI Toolkit の入力統合、
InputSystemUIInputModule - unity-xr — XR コントローラー入力、トラッキング対象デバイス