The new Input System
Assets/
Scripts/
Settings/
Project settings
you already havethis lesson addsthis lesson retires
Three scripts you wrote still call Input directly: PlayerMovement reads GetAxisRaw, CharacterSwitcher reads the number keys, SkillCaster reads Q, E and R. All three are locked to a keyboard, which is a problem, because tab 05 puts this on a phone.
The Input System lets you define an action once and bind keyboard, gamepad and touch to it. After this lesson none of your gameplay scripts know which device the player is holding.
Devices on the left, one action asset in the middle, your gameplay code on the right.
Install and switch
- 1
Package Manager → Input System → Install. Unity will ask to restart; say yes.
- 2
→ Both while you migrate.
- 3
Project: , name it PlayerControls, double-click to open the editor.
- 4
Tick Generate C# Class and press Apply — Unity writes a wrapper class for you.
Build the action map
- 1
Add an Action Map called Gameplay.
- 2
Action Move → Action Type Value → Control Type Vector2. Add a 2D Vector Composite binding: W/A/S/D. Add another binding: Gamepad left stick.
- 3
Action Look → Value → Vector2 → bind Mouse Delta and Gamepad right stick.
- 4
Actions Jump and Attack → Action Type Button → bind Space / South button and Left Mouse / West button.
- 5
Actions Skill1 / Skill2 / Skill3 → Button → bind Q, E, R. These replace the keys SkillCaster reads today.
- 6
Action SwapCharacter → Value / Axis → bind the 1, 2, 3 keys. These replace what CharacterSwitcher reads today.
Read it in code
using UnityEngine;
using UnityEngine.InputSystem;
public class InputRouter : MonoBehaviour
{
// filled by the generated class
private PlayerControls controls;
public Vector2 Move { get; private set; }
public Vector2 Look { get; private set; }
public bool JumpPressed { get; private set; }
void Awake()
{
controls = new PlayerControls();
controls.Gameplay.Move.performed += ctx => Move = ctx.ReadValue<Vector2>();
controls.Gameplay.Move.canceled += ctx => Move = Vector2.zero; // never forget this line
controls.Gameplay.Look.performed += ctx => Look = ctx.ReadValue<Vector2>();
controls.Gameplay.Look.canceled += ctx => Look = Vector2.zero;
controls.Gameplay.Jump.performed += ctx => JumpPressed = true;
controls.Gameplay.Attack.performed += ctx => GetComponent<SkillCaster>().TryCast(0);
}
void OnEnable() => controls.Enable(); // no Enable = no input at all
void OnDisable() => controls.Disable();
void LateUpdate() => JumpPressed = false; // one-frame flag
}performed fires when the input starts or changes; canceled fires when it is released. Forgetting canceled means the character walks forever.
Move is a Vector2 (x, y). In 3D you map it to (x, 0, y) — the y of the stick becomes world Z.
A second action map called UI can be enabled while Gameplay is disabled — that is how pause menus stop the player from moving.
Retire the three old readers
This is the tidy-up that makes the whole tab worth it. Delete every Input.GetAxis, Input.GetKey and Input.GetMouseButton in your project and route them through InputRouter instead.
// 1 — PlayerMovement.cs
- float h = Input.GetAxisRaw("Horizontal");
- float v = Input.GetAxisRaw("Vertical");
- Vector3 input = new Vector3(h, 0f, v).normalized;
+ Vector3 input = new Vector3(router.Move.x, 0f, router.Move.y).normalized;
// 2 — CharacterSwitcher.cs
- for (int i = 0; i < characters.Count && i < 9; i++)
- if (Input.GetKeyDown(KeyCode.Alpha1 + i)) Select(i);
+ // in InputRouter.Awake:
+ controls.Gameplay.SwapCharacter.performed += c => switcher.Select((int)c.ReadValue<float>() - 1);
// 3 — SkillCaster.cs
- for (int i = 0; i < skills.Count && i < keys.Length; i++)
- if (Input.GetKeyDown(keys[i])) TryCast(i);
+ // in InputRouter.Awake:
+ controls.Gameplay.Skill1.performed += _ => caster.TryCast(0);
+ controls.Gameplay.Skill2.performed += _ => caster.TryCast(1);
+ controls.Gameplay.Skill3.performed += _ => caster.TryCast(2);Using it in the movement script
[SerializeField] private InputRouter input;
void Update()
{
Vector3 dir = new Vector3(input.Move.x, 0f, input.Move.y);
// ... rest is identical to the old script
}✓ PlayerInput component
✓ Generated C# class