Topic 9 of 15 14 min intermediate

The Input System

Actions, maps, and device support

Unity has two input systems, and most tutorials you find use the old one. Knowing which you are looking at saves a lot of confusion, because their code does not mix.

Old vs new

Input Manager (old)Input System (new)Note
Input.GetKey(KeyCode.W)moveAction.ReadValue<Vector2>()New reads a value, not a key.
Input.GetAxis("Horizontal")Action with a 2D vector bindingBindings live in an asset.
Built in, nothing to installPackage Manager installExtra setup, far more capable.
Rebinding is manual workRebinding is built inA real accessibility win.
Polling onlyPolling or callbacksEvents avoid missed presses.
Installing the new package sets the active handler to Input System Package and the old Input.GetKey calls start throwing InvalidOperationException. If you need both during a migration, set Active Input Handling to Both in Player Settings.

The mental model

The new system separates what the player wants to do from which button they pressed.

  • Action — an intent, like "Jump" or "Move".
  • Binding — a control that triggers it. One action can have many.
  • Action Map — a group of actions for one context, like Gameplay or Menu.
  • Action Asset — the file holding all of it.

Your code asks "is the player moving?" and never asks "is W held?". Add a gamepad stick as a second binding and the same code supports controllers with no changes.

Setting it up

  1. 1
    Install the package

    Window → Package Manager → Input System. Unity restarts the editor afterwards.

  2. 2
    Create an Input Actions asset

    Right-click in the Project window: Create → Input Actions. Double-click to open the editor.

  3. 3
    Add a map and some actions

    A Gameplay map with Move (Value, Vector2) and Jump (Button) covers most games.

  4. 4
    Bind controls

    Give Move a 2D Vector composite for WASD plus the gamepad left stick. Give Jump Space plus the south button.

  5. 5
    Tick Generate C# Class

    In the asset's Inspector. That produces a typed wrapper you can use directly.

Reading input

PlayerInputHandler.cs
C#
using UnityEngine;
using UnityEngine.InputSystem;

public class PlayerInputHandler : MonoBehaviour
{
    private PlayerControls controls;   // the generated class
    private Vector2 moveInput;

    private void Awake()
    {
        controls = new PlayerControls();

        // Events: never miss a press, even between frames
        controls.Gameplay.Jump.performed += OnJump;
    }

    private void OnEnable()  => controls.Gameplay.Enable();
    private void OnDisable() => controls.Gameplay.Disable();

    private void OnDestroy()
    {
        controls.Gameplay.Jump.performed -= OnJump;
        controls.Dispose();
    }

    private void Update()
    {
        // Polling: right for continuous values like movement
        moveInput = controls.Gameplay.Move.ReadValue<Vector2>();
    }

    private void OnJump(InputAction.CallbackContext context)
    {
        jumpQueued = true;
    }
}
Poll continuous values such as movement; use callbacks for discrete presses such as jump or fire. Callbacks cannot be missed by a slow frame, which is exactly the FixedUpdate trap from the lifecycle topic.
You must call Enable(). A brand-new action asset produces no input at all until its map is enabled — the most common "nothing happens" moment with the new system.

Switching contexts

Action maps make pausing trivial. Disable Gameplay, enable UI, and movement keys stop driving the player while menu navigation starts working — no isPaused checks scattered through your code.

C#
public void Pause()
{
    controls.Gameplay.Disable();
    controls.UI.Enable();
    Time.timeScale = 0f;
}

public void Resume()
{
    controls.UI.Disable();
    controls.Gameplay.Enable();
    Time.timeScale = 1f;
}

Rebinding

Interactive rebinding in a few lines

Letting players remap controls is a real accessibility feature, and the new system makes it genuinely simple.

C#
public void StartRebind(InputAction action, int bindingIndex)
{
    action.Disable();   // required while rebinding

    action.PerformInteractiveRebinding(bindingIndex)
        .WithControlsExcluding("Mouse")
        .OnMatchWaitForAnother(0.1f)
        .OnComplete(op =>
        {
            op.Dispose();
            action.Enable();
            SaveBindings(action);
        })
        .Start();
}

private void SaveBindings(InputAction action)
{
    PlayerPrefs.SetString("bindings", action.actionMap.asset.SaveBindingOverridesAsJson());
}

Touch

Touch is just another device. An on-screen stick can bind to the same Move action as WASD, so your movement code never learns it is running on a phone.

For quick mobile work the library has ready-made Touch Joystick and Swipe Input Controller scripts.

What to take away

  • Check which input system a tutorial uses before following it.
  • Actions describe intent; bindings describe buttons.
  • Call Enable() or you get no input at all.
  • Poll continuous values, use callbacks for discrete presses.
  • Action maps make pause and menu contexts clean.
  • Rebinding is built in — use it.