Unity Term Book
Scripting & Lifecycle

Input System

Unity's modern Input System package — flexible remapping, multi-device support, and event-driven actions — replaces the legacy Input.GetKey() polling API.

Imagine...

The old Input System is staff calling every 0.016s to ask “Any customers yet?” (polling). The new Input System installs a doorbell (events) — you only hear when someone presses it. Action Maps are like a dispatch board — the same “Confirm” button means Navigate Accept in a menu and Jump in gameplay. No `if (context == menu)` spaghetti.

The concept in detail

An Input Actions Asset is a .inputactions file that holds every binding. It is organized into Action Maps (Gameplay, UI, Vehicle…) → each Map has Actions (Move, Jump, Fire…) → each Action has Bindings (keys, sticks, gamepad buttons…).

Event-driven: Subscribe to action.started, action.performed, action.canceled. Call context.ReadValue<Vector2>() for values. No Update polling required.

Player Input component: Attach it to a GameObject to wire events automatically. Supports Messages, C# Events, or Unity Events.

Runtime remapping: action.AddBinding() and InputActionRebindingExtensions.PerformInteractiveRebinding() let players change keybinds in a Settings menu.

Diagram: Input System architecture

⌨️ Keyboard
🎮 Gamepad
📱 Touch
🖱 Mouse
↓ Device Input

Input Actions Asset (.inputactions)

Action Map: GameplayAction Map: UIAction Map: Vehicle
↓ Binding resolution

Actions: Move, Jump, Fire, Interact...

started / performed / canceled events

↓ C# Events

PlayerController

OnMove(ctx)

UINavigator

OnNavigate(ctx)

VehicleDriver

OnSteer(ctx)

Hands-on steps

1

Install the Input System package

Window → Package Manager → Input System → Install. Restart when prompted.

2

Create an Input Actions Asset

Assets → Create → Input Actions. Add Action Maps, Actions, and Bindings for each key/button.

3

Generate a C# class

Select the .inputactions file → Inspector → check "Generate C# Class" → Apply → Unity emits a wrapper class.

4

Subscribe / unsubscribe events

OnEnable: _actions.Gameplay.Jump.performed += OnJump; OnDisable: unsubscribe the same way.

Interactive simulator

Press keys (or the buttons below) and watch events reach the right listener for the active Action Map.

Active Map:

Virtual Input

Event Log

Press a key to see events...

Map: Gameplay|Events fired: 0

Code example

Basic

Use a generated C# class with event subscriptions.

using UnityEngine;
using UnityEngine.InputSystem;

public class PlayerController : MonoBehaviour
{
  private GameControls _actions; // Generated C# class
  private Rigidbody    _rb;
  private Vector2      _moveInput;

  void Awake()
  {
      _rb      = GetComponent<Rigidbody>();
      _actions = new GameControls();
  }

  void OnEnable()
  {
      _actions.Gameplay.Enable();
      _actions.Gameplay.Move.performed  += OnMove;
      _actions.Gameplay.Move.canceled   += OnMove;
      _actions.Gameplay.Jump.performed  += OnJump;
  }

  void OnDisable()
  {
      _actions.Gameplay.Move.performed  -= OnMove;
      _actions.Gameplay.Move.canceled   -= OnMove;
      _actions.Gameplay.Jump.performed  -= OnJump;
      _actions.Gameplay.Disable();
  }

  void OnMove(InputAction.CallbackContext ctx)
      => _moveInput = ctx.ReadValue<Vector2>();

  void OnJump(InputAction.CallbackContext ctx)
      => _rb.AddForce(Vector3.up * 5f, ForceMode.Impulse);

  void FixedUpdate()
      => _rb.velocity = new Vector3(_moveInput.x * 5f, _rb.velocity.y, _moveInput.y * 5f);
}

Code example

Advanced

Interactive rebinding — let players change keybinds at runtime.

using UnityEngine;
using UnityEngine.InputSystem;
using TMPro;

public class KeyRebinder : MonoBehaviour
{
  [SerializeField] private InputActionReference jumpAction;
  [SerializeField] private TextMeshProUGUI bindingLabel;
  private InputActionRebindingExtensions.RebindingOperation _rebindOp;

  public void StartRebind()
  {
      jumpAction.action.Disable();
      bindingLabel.text = "Press any key...";

      _rebindOp = jumpAction.action
          .PerformInteractiveRebinding()
          .WithControlsExcluding("Mouse")
          .OnMatchWaitForAnother(0.1f)
          .OnComplete(op => {
              op.Dispose();
              jumpAction.action.Enable();
              bindingLabel.text = InputControlPath.ToHumanReadableString(
                  jumpAction.action.bindings[0].effectivePath);
              // Persist binding overrides
              PlayerPrefs.SetString("JumpBinding", jumpAction.action.SaveBindingOverridesAsJson());
          })
          .Start();
  }
}

📌 Quick recap

  • Enable/Disable ActionMaps by context (Gameplay ↔ UI)
  • Subscribe in OnEnable, unsubscribe in OnDisable
  • performed = pressed; canceled = released
  • Generate a C# class → cleaner API + IntelliSense

⚠️ Common mistakes

  • ❌ Forgetting Enable() on the Action Map

    Actions never fire even after subscribe — silent failure

    ✅ _actions.Gameplay.Enable() in OnEnable

  • ❌ Forgetting Unsubscribe in OnDisable

    Memory leak — events call into destroyed objects

    ✅ Always mirror Subscribe/Unsubscribe with OnEnable/OnDisable