If you have been following Unity tutorials for a while, you have probably used something like Input.GetAxis("Horizontal") or Input.GetKeyDown(KeyCode.Space) to handle player input. That approach works, but it belongs to Unity's older Input Manager system, and it has real limitations — especially once you want to support multiple control schemes, gamepads, or mobile touch input.
Unity's newer Input System package was designed to solve all of those problems. It is more flexible, more powerful, and much better organized once you understand how it is structured. The downside is that it looks more complicated when you first open it, which is exactly why most beginners avoid it longer than they should.
This guide fixes that. We will go from zero — installing the package — all the way through understanding Action Maps, writing a working movement script, and migrating your old Input Manager code to the new system. No skipped steps, no assumed knowledge.
What Is the Unity Input System?
The Unity Input System is an official Unity package that handles all input from the player — keyboard, mouse, gamepad, touch, joystick, and more — in a single, unified, configurable system.
Instead of writing if (Input.GetKey(KeyCode.W)) directly in your script and hard-coding it to the W key, the Input System lets you define an abstract "action" called something like "Move" or "Jump," and then separately assign which physical buttons or keys trigger that action. Your code only cares about the action, not which button causes it.
This separation is the entire point of the system, and once it clicks, it changes how you think about input entirely. Your movement script does not care if the player pressed W on a keyboard, pushed the left stick on an Xbox controller, or tapped a virtual joystick on a phone. All of those map to the same "Move" action, and your code responds to the action.
Why It Matters for Beginners
You might be thinking: "Input.GetAxis works fine — why do I need to learn something more complicated?" That is a fair question, and honestly, if you are building a solo desktop game that will never support controllers or mobile, the old system may be enough.
But here is where the old system breaks down:
- You want players to use either a keyboard or a gamepad — you need to manually check both in the same if statement.
- You want to let players remap their own keys — the old Input Manager has no built-in support for this at runtime.
- You want to add mobile touch controls later — Input.GetAxis has no touch concept at all.
- You want to support multiple players on the same machine with different controllers — the old system has no clean way to handle this.
The new Input System handles all of these out of the box. That is why learning it now, even as a beginner, will save you a significant amount of painful rewriting later.
Input System vs Input Manager: Key Differences
| Feature | Old Input Manager | New Input System |
| Setup location | Edit > Project Settings > Input Manager | Input Action Asset (.inputactions file) |
| Accessing input in code | Input.GetAxis(), Input.GetKeyDown() | Action callbacks or PlayerInput component |
| Gamepad support | Manual, limited | Built-in, automatic device detection |
| Key remapping at runtime | Not supported without custom code | Built-in binding override system |
| Multiple players / split-screen | Very difficult | Supported natively with PlayerInputManager |
| Mobile touch input | Separate Input.touches API | Unified with all other inputs |
| Learning curve | Low | Medium — but pays off quickly |
Part 1: Installation
The Input System does not come installed by default in most Unity projects. You need to add it through the Package Manager.
Step 1: Open the Package Manager
- In Unity, go to the top menu and click Window > Package Manager.
- In the top-left dropdown inside the Package Manager, change it from "In Project" to "Unity Registry". This shows all available official Unity packages.
Step 2: Find and Install the Input System
- In the search box, type Input System.
- Click the result named exactly "Input System" (published by Unity Technologies).
- Click Install in the bottom-right corner.
- Unity will show a warning dialog: This project is currently using the old input system. Do you want to enable the new one? Click Yes. Unity will restart.
Step 3: Verify Active Input Handling
- After Unity restarts, go to Edit > Project Settings > Player.
- Scroll to Other Settings and find Active Input Handling.
- Set it to "Input System Package (New)" for a clean new project, or "Both" if you are migrating an existing project.
Choosing "Both" lets old Input.GetAxis calls and the new Input System coexist — essential when migrating. Choosing "Input System Package (New)" disables the old system immediately. For any existing project with old input code still in it, always start with "Both".
Part 2: Core Concepts You Must Understand
Before writing any code, you need to understand four concepts that the Input System is built around. These show up everywhere, and confusion about them is the number one reason beginners get stuck.
1. Input Action
An Input Action is an abstract thing your game cares about — like "Move", "Jump", "Fire", or "Look". It has no idea which physical button causes it. That connection is made separately through bindings.
2. Binding
A Binding connects an Input Action to a physical control. For example, the "Jump" action might be bound to the Space bar on keyboard and the South button (A on Xbox, Cross on PlayStation) on a gamepad. One action, multiple bindings.
3. Action Map
An Action Map is a named group of Input Actions. You might have a "Player" Action Map with Move, Jump, and Sprint, and a "UI" Action Map with Navigate, Submit, and Cancel. Only the active Action Map is processed — this is how you switch input contexts, like disabling player input while a menu is open.
4. Input Action Asset
An Input Action Asset is a file (extension: .inputactions) that stores all your Action Maps, Actions, and Bindings. It lives in your Project window and opens in a dedicated editor. Think of it as the single organized settings file for all input in your game.
This part usually confuses new users, because the old Input Manager was a hidden project settings window — never a visible file. The Input Action Asset being a real file in your project is actually better: you can duplicate it, version-control it, and share it across projects easily.
Part 3: Creating Your First Input Action Asset
Let's build this from scratch so you know exactly what every piece is.
Step 1: Create the Asset
- In your Project window, right-click inside your Assets folder (or an Assets/Input subfolder).
- Choose Create > Input Actions.
- Name the file PlayerInputActions.
- Double-click it to open the Input Action editor.
Step 2: Create an Action Map
- In the left column labeled "Action Maps", click the + button.
- Name the Action Map Player.
Step 3: Create Actions
- With "Player" selected, click the + in the "Actions" column.
- Name the first action Move. In the Properties panel on the right, set Action Type to Value and Control Type to Vector2. This returns a 2D direction, not just a true/false.
- Create a second action named Jump. Set Action Type to Button. Jump is pressed or not — no direction needed.
Step 4: Add Bindings to Move
- Right-click the Move action and choose Add 2D Vector Composite. This creates four directional sub-bindings Unity combines into a single Vector2.
- Click Up and set its Path to W [Keyboard].
- Repeat: Down = S, Left = A, Right = D.
- Right-click Move again and choose Add Binding. Set Path to Left Stick [Gamepad] for controller support.
Step 5: Add Bindings to Jump
- Click Jump, then click + and choose Add Binding.
- Set Path to Space [Keyboard].
- Add a second binding: Button South [Gamepad] (A on Xbox, Cross on PlayStation).
Step 6: Save the Asset
Click Save Asset at the top of the editor. Changes do not persist until you do this. This is the most common beginner mistake with the Input Action editor — everything looks correct but nothing works because the save step was skipped.
Part 4: Using the Input System in a Script
There are two main ways to read input from your Input Action Asset in a script. We will cover both, starting with the simpler one.
Method 1: The PlayerInput Component (Recommended for Beginners)
The PlayerInput component sits on your Player GameObject, reads the Input Action Asset, and automatically calls matching functions in your script when actions are triggered.
Setting It Up
- Select your Player GameObject in the Hierarchy.
- Click Add Component and search for Player Input.
- Drag your PlayerInputActions asset into the Actions field.
- Set Default Map to Player.
- Set Behavior to Send Messages.
The Script
Create a new C# script named PlayerMovementNew, open it, replace all contents with the following, and attach it to the same Player object.
using UnityEngine;
using UnityEngine.InputSystem;
public class PlayerMovementNew : MonoBehaviour
{
public float moveSpeed = 6f;
public float gravity = -9.81f;
public float jumpHeight = 1.5f;
private CharacterController controller;
private Vector3 velocity;
private bool isGrounded;
private Vector2 moveInput;
private bool jumpPressed;
void Start()
{
controller = GetComponent<CharacterController>();
}
void OnMove(InputValue value)
{
moveInput = value.Get<Vector2>();
}
void OnJump(InputValue value)
{
if (value.isPressed)
{
jumpPressed = true;
}
}
void Update()
{
isGrounded = controller.isGrounded;
if (isGrounded && velocity.y < 0f)
{
velocity.y = -2f;
}
Vector3 move = transform.right * moveInput.x + transform.forward * moveInput.y;
controller.Move(move * moveSpeed * Time.deltaTime);
if (jumpPressed && isGrounded)
{
velocity.y = Mathf.Sqrt(jumpHeight * -2f * gravity);
}
jumpPressed = false;
velocity.y += gravity * Time.deltaTime;
controller.Move(velocity * Time.deltaTime);
}
}
Press Play. Your character now moves with WASD or a gamepad left stick, and jumps with Space or the gamepad South button — with zero extra code changes for controller support.
How "Send Messages" Works
When Behavior is set to "Send Messages", the PlayerInput component calls functions named On + ActionName on scripts attached to the same GameObject. The "Move" action calls OnMove(InputValue value). The "Jump" action calls OnJump(InputValue value). Unity finds these by name automatically — you do not register them anywhere. The names must match exactly, including capitalization.
Method 2: Direct Script Reference (More Control)
When you need input logic in a script that is not on the Player GameObject — for example, an input manager script — you reference the asset directly in code.
First, select your PlayerInputActions asset in the Project window, tick Generate C# Class in the Inspector, and click Apply. Unity creates a typed C# wrapper you can use directly.
using UnityEngine;
using UnityEngine.InputSystem;
public class PlayerMovementDirect : MonoBehaviour
{
public float moveSpeed = 6f;
public float gravity = -9.81f;
public float jumpHeight = 1.5f;
private CharacterController controller;
private PlayerInputActions inputActions;
private Vector3 velocity;
private Vector2 moveInput;
void Awake()
{
inputActions = new PlayerInputActions();
}
void OnEnable()
{
inputActions.Player.Enable();
inputActions.Player.Jump.performed += OnJump;
}
void OnDisable()
{
inputActions.Player.Jump.performed -= OnJump;
inputActions.Player.Disable();
}
private void OnJump(InputAction.CallbackContext context)
{
if (controller.isGrounded)
{
velocity.y = Mathf.Sqrt(jumpHeight * -2f * gravity);
}
}
void Start()
{
controller = GetComponent<CharacterController>();
}
void Update()
{
moveInput = inputActions.Player.Move.ReadValue<Vector2>();
if (controller.isGrounded && velocity.y < 0f)
{
velocity.y = -2f;
}
Vector3 move = transform.right * moveInput.x + transform.forward * moveInput.y;
controller.Move(move * moveSpeed * Time.deltaTime);
velocity.y += gravity * Time.deltaTime;
controller.Move(velocity * Time.deltaTime);
}
}
Key Differences Explained Line by Line
Awake() initializes the input actions before Start() runs on any other script, ensuring input is ready before anything reads it.
OnEnable() / OnDisable() are where you enable or disable the Action Map and subscribe or unsubscribe from action callbacks. The += adds your function to the event. The -= removes it. Always pair them — a missing -= is one of the most common causes of jump firing twice per press after a scene reload.
ReadValue<Vector2>() is called each frame in Update() to get the current stick or WASD direction. This is the polling model, similar in feel to the old Input.GetAxis().
Jump.performed += fires exactly once when the button is first pressed, not every frame it is held down. This event-driven model is the correct approach for one-shot actions like jumping, interacting, or firing.
Part 5: Migrating Old Input Manager Code
If you have an existing project using the old Input Manager, here is how to convert the most common patterns. Keep Active Input Handling set to "Both" during this process.
Movement (Axis Input)
| Old Code | New Code (Direct Method) |
| float x = Input.GetAxis("Horizontal"); | Vector2 move = inputActions.Player.Move.ReadValue<Vector2>(); float x = move.x; |
| float z = Input.GetAxis("Vertical"); | float z = move.y; |
Jumping (Button Press)
| Old Code | New Code (Event Callback) |
| if (Input.GetButtonDown("Jump")) | inputActions.Player.Jump.performed += ctx => { /* jump logic */ }; |
Single Key Detection
| Old Code | New Code (Polling) |
| if (Input.GetKeyDown(KeyCode.E)) | if (inputActions.Player.Interact.WasPressedThisFrame()) |
Mouse Position
| Old Code | New Code |
| Vector3 pos = Input.mousePosition; | Vector2 pos = Mouse.current.position.ReadValue(); |
A common mistake beginners make during migration is switching to "Input System Package (New)" before all old Input.GetAxis calls have been replaced. This breaks everything at once and produces a wall of null reference errors. Always migrate file by file with "Both" mode active, and only switch to new-only once every old call is gone.
Troubleshooting Guide
Problem: OnMove or OnJump is never called.
Likely cause: Behavior is not set to "Send Messages", or the script is not on the same GameObject as PlayerInput.
Fix: Confirm both components are on the same object. Confirm Behavior is "Send Messages". Check function names are exactly "On" + the action name, case-sensitive.
Problem: Input works in editor but not in a build.
Likely cause: The Input Action Asset is not referenced in the scene, or Active Input Handling changed after the last build.
Fix: Ensure the asset is assigned to the PlayerInput component in the scene. Rebuild after any Project Settings change.
Problem: Gamepad detected but movement does not work.
Likely cause: The gamepad binding is missing from the Move action in the asset.
Fix: Open the Input Action Asset, expand Move, and confirm a "Left Stick [Gamepad]" binding exists in the active Action Map.
Problem: Jump fires multiple times per press.
Likely cause: Jump callback was subscribed with += more than once without a matching -= unsubscription.
Fix: Always pair += in OnEnable() with -= in OnDisable(). Confirm OnEnable() is not called more than once unexpectedly.
Problem: All input stopped working after switching to the new Input System.
Likely cause: Active Input Handling was set to "Input System Package (New)" while old Input.GetAxis calls still exist.
Fix: Set Active Input Handling back to "Both" temporarily and finish migrating the remaining old calls.
Problem: Move returns zero even with keys pressed.
Likely cause: Action Map was never enabled (direct method), or Move's Control Type is set to Button instead of Vector2.
Fix: Add inputActions.Player.Enable() in OnEnable(). Verify Move's Control Type is Vector2 in the Input Action editor.
A Brief Note on Mobile Touch Input
The Input System supports mobile touch input through the same action-based architecture used throughout this guide. A touchscreen tap maps to the same "Jump" action as the Space bar. A virtual on-screen joystick feeds into the same "Move" action as WASD. Your movement script requires zero changes to support touch once the bindings are set up correctly.
Unity provides On-Screen Stick and On-Screen Button components, included with the Input System package, that handle the bridge between screen touches and your Input Actions. The setup requires working with Unity's UI Canvas system, which deserves its own dedicated walkthrough.
A full guide covering Unity mobile touch input, on-screen controls, and virtual joystick setup is coming soon — and it will connect directly to the Input Action Asset you built in this guide, so nothing needs to be rebuilt from scratch.
Frequently Asked Questions
What is the Unity Input System?
It is an official Unity package that handles all player input — keyboard, gamepad, mouse, touch, and more — through a centralized, action-based system rather than hard-coded key checks in individual scripts.
Is the new Input System better than the old Input Manager?
For most projects, yes. It supports multiple control schemes, built-in gamepad detection, runtime key remapping, and multiple players without extra code. The old Input Manager is simpler to start with but hits real limitations as projects grow.
How do I install the Input System in Unity?
Open Window > Package Manager, switch to "Unity Registry", search for "Input System", click Install, confirm the restart prompt, then set Active Input Handling in Edit > Project Settings > Player > Other Settings.
What is an Action Map in Unity?
An Action Map is a named group of Input Actions. A "Player" Action Map holds Move and Jump. A "UI" Action Map holds Navigate and Submit. You enable and disable Action Maps at runtime to switch input contexts.
What is a Binding in the Unity Input System?
A Binding connects an abstract Input Action to a specific physical control — for example, connecting "Jump" to both the Space bar and the gamepad's South button so either triggers the same action.
How do I read movement input with the new Input System?
Create a Move action with Action Type set to Value and Control Type set to Vector2. Use OnMove(InputValue value) with the PlayerInput component, or call inputActions.Player.Move.ReadValue<Vector2>() in Update() with the direct method.
Why is OnMove not being called in my script?
Either the PlayerInput component's Behavior is not "Send Messages", the script is on a different GameObject than PlayerInput, or the function name does not exactly match "On" + the action name.
Do I still need PlayerInput component if I use the direct method?
No. The PlayerInput component is only needed for "Send Messages" and "Invoke Unity Events" behaviors. The direct method manages everything through code and does not require the component.
What does "performed" mean in Input System callbacks?
The "performed" callback fires when an action is fully activated — a button fully pressed, or a stick moved past its threshold. There are also "started" (first contact) and "canceled" (released) phases for more granular control.
How do I make jump fire only once per press?
Subscribe to the "performed" callback instead of reading a value in Update(). The performed callback fires exactly once when the button is pressed, not every frame it is held down.
Why is my character moving twice as fast after switching input systems?
Movement is probably being applied in both a callback and in Update() at the same time. Pick one approach — polling in Update() or an event callback — and remove the other.
Can I use both the new Input System and the old Input Manager simultaneously?
Yes. Set Active Input Handling to "Both" in Project Settings. Both systems will function in parallel, which is useful when migrating an existing project gradually.
How do I add gamepad support with the Input System?
In the Input Action Asset, add a second binding to each action pointing to the gamepad control — Left Stick for Move, Button South for Jump. Unity detects connected gamepads automatically. No extra code is needed.
How do I disable input when a pause menu opens?
Call inputActions.Player.Disable() when the menu opens and inputActions.Player.Enable() when it closes. With the PlayerInput component, you can also call playerInput.SwitchCurrentActionMap("UI") to activate UI input instead.
What is the difference between Send Messages, Broadcast Messages, and Invoke Unity Events?
"Send Messages" calls OnActionName() functions on the same GameObject only. "Broadcast Messages" calls them on the same object and all children. "Invoke Unity Events" connects actions to functions through the Inspector's Unity Event system, like a button's onClick.
Why does my jump callback fire three times per press?
The += subscription was called multiple times — typically because OnEnable() ran more than once without a matching OnDisable() unsubscription in between. Always pair every += with a -= in OnDisable().
What is C# code generation for Input Action Assets?
An option in the Inspector for your .inputactions file that generates a typed C# class matching your Action Maps and Actions. It removes magic strings, adds autocomplete, and makes the direct method cleaner to write.
Does the new Input System support mobile touch input?
Yes. The same actions work for touch. Unity's On-Screen Stick and On-Screen Button components feed touch input into your existing actions. A full mobile touch input guide covering this setup in detail is coming soon.
Key Takeaways
- The Unity Input System replaces hard-coded key checks with abstract Input Actions that work across keyboard, gamepad, and touch without code changes.
- Input Action Assets store all your Action Maps, Actions, and Bindings in one visible, editable file.
- The PlayerInput component with "Send Messages" is the fastest setup for beginners — matching functions are called automatically by name.
- The direct script method offers more control and is better for larger or more complex projects.
- Always enable Action Maps before reading input, and always pair += with -= in OnDisable().
- Use "Both" mode during migration — never switch to new-only while old Input calls still exist.
Action Steps
- Install the Input System package through the Package Manager and verify Active Input Handling is set correctly.
- Create a PlayerInputActions asset with a "Player" Action Map containing Move (Vector2) and Jump (Button).
- Add WASD + gamepad left stick bindings to Move, and Space + gamepad South button to Jump.
- Add the PlayerInput component to your Player, assign the asset, and set Behavior to "Send Messages".
- Attach the PlayerMovementNew script and confirm both keyboard and gamepad movement work in Play mode.
- Once comfortable, enable C# code generation on the asset and try rewriting the script using the direct method.
Learning Roadmap
- Get basic keyboard and gamepad movement working using this guide's PlayerMovementNew script.
- Practice switching Action Maps at runtime — disable "Player" input when a pause menu opens, enable "UI".
- Enable C# code generation and migrate to the typed direct method for cleaner, autocomplete-friendly code.
- Explore the Unity Rigidbody system for physics objects that interact with your Input-System-driven player.
- Work through on-screen touch control setup once the mobile input guide is published.
Next Topics To Learn
- Unity Rigidbody Explained for Beginners — understand physics-based movement alongside your Character Controller and Input System setup.
- Unity Mobile Optimization Guide — prepare performance before adding touch input and building for mobile.
- Unity Mobile Touch Input and On-Screen Controls — coming soon.
No comments:
Post a Comment