Unity Input System Tutorial for Player Controls
Unity Input System Tutorial for Player Controls
Welcome to this comprehensive guide on Unity's new Input System. If you've been working with Unity for a while, you're likely familiar with the traditional Input.GetKey method. While functional, the new system offers a more powerful, flexible, and modular way to handle player controls, making it easier to support multiple platforms and devices. This tutorial will walk you through everything you need to know, from initial setup to scripting responsive player movement.
Getting Started: Installing the Input System
Before we can dive into creating controls, we first need to install the new Input System package. It's not included by default to ensure backward compatibility with older projects.
To get started, open your Unity project and navigate to the Package Manager by going to Window > Package Manager.[1][2] In the Package Manager window, make sure you're viewing packages from the "Unity Registry".[2][3] Use the search bar to find the "Input System" package and click "Install".[3][4]
Once the installation is complete, a warning message will appear, asking if you want to enable the new input backends.[4][5] Clicking "Yes" will restart the Unity Editor and set the new Input System as the active input handler, disabling the old UnityEngine.Input manager.[1][5] For most new projects, this is the recommended approach. However, you also have the option to use both systems side-by-side by going to Edit > Project Settings > Player and under "Other Settings", setting "Active Input Handling" to "Both".[4][5] This can be useful when migrating an existing project.
The Core Concept: Input Action Assets
The heart of the new Input System is the "Input Action Asset". This is a dedicated asset in your project that stores all your input configurations. It decouples the input logic from your game code, which means you can change keybindings and add support for new devices without ever touching your scripts.[4]
To create one, right-click in your Project window and go to Create > Input Actions.[4][6] Give it a descriptive name like "PlayerControls". Double-clicking this asset will open the Input Action editor, a powerful interface for defining your game's control scheme.[4][7] It's a good practice to check the "Auto-Save" box at the top of this window to ensure your changes are always saved.[4]
Understanding Action Maps, Actions, and Bindings
The Input Action editor is organized into three main columns: Action Maps, Actions, and Properties (Bindings).[6]
Action Maps: Think of these as different control contexts or states in your game. For example, you might have one Action Map for player movement ("Gameplay"), another for navigating menus ("UI"), and a third for when the player is driving a vehicle ("Driving").[6][8][9] You can switch between these maps at runtime to change which controls are active.[8]
Actions: Within each Action Map, you define specific Actions. An Action represents a logical input, like "Move", "Jump", or "Fire".[6][10] It doesn't care what button or key triggers it; it only represents the intended action.[4]
Bindings: This is where you connect an Action to a physical input. For a "Jump" action, you might create a binding for the "Space" key on the keyboard and another for the "South Button" (A on an Xbox controller, X on a PlayStation controller) on a gamepad.[11]
Setting Up Your First Player Controls
Let's create a basic control scheme for a player. In your "PlayerControls" Input Action asset, you'll likely see a default "Player" Action Map. If not, you can create one by clicking the "+" icon in the Action Maps column.[6][11]
Now, let's define some actions in the middle column:
Move Action: Click the "+" next to "Actions" and name it "Move". In the Properties panel on the right, set the "Action Type" to "Value" and the "Control Type" to "Vector 2".[3][12] A Vector2 is perfect for representing 2D movement (up/down, left/right).
Jump Action: Create another action and name it "Jump". Keep its "Action Type" as "Button", which is suitable for single-press events.[3]
Next, we need to create bindings for these actions.
For the Move Action: Click the "+" next to the "Move" action and select "Add Up/Down/Left/Right Composite". This will create four bindings. Assign them to the "W", "S", "A", and "D" keys on the keyboard, respectively. You can add another binding for a gamepad by clicking the "+" again, selecting "Path", and then navigating to Gamepad > Left Stick.[12][13] The system is smart enough to interpret the 2D input from the joystick.
For the Jump Action: Select the "Jump" action. Click the "+" next to "Binding" and set the "Path" to the "Space" key on the keyboard. Add another binding and set its path to Gamepad > Button South to support controllers.[3][13]
Connecting Inputs to Your Scripts
Now that we have our Input Action Asset configured, it's time to make our character respond to these inputs. There are a few ways to do this, but we'll focus on two popular methods: using the PlayerInput component and generating a C# class.
Method 1: The PlayerInput Component (Unity Events)
This is a beginner-friendly, component-based approach.
Add the Component: Select your player GameObject in the scene and add a "Player Input" component.[14][15]
Assign the Asset: Drag your "PlayerControls" Input Action Asset into the "Actions" slot on the PlayerInput component.[12][15]
Set the Behavior: Change the "Behavior" dropdown to "Invoke Unity Events". This will expose events in the inspector for each of your defined actions.[6][16]
Create a Player Script: Create a C# script, let's call it PlayerController, and attach it to your player GameObject.
Write the Handler Methods: In your PlayerController script, you need to create public methods that will be called by the Unity Events. These methods must take an InputAction.CallbackContext parameter.
codeC#
using UnityEngine;
using UnityEngine.InputSystem;
public class PlayerController : MonoBehaviour
{
private Vector2 moveInput;
public void OnMove(InputAction.CallbackContext context)
{
moveInput = context.ReadValue<Vector2>();
}
public void OnJump(InputAction.CallbackContext context)
{
if (context.performed)
{
Debug.Log("Jump action was performed!");
// Add your jump logic here
}
}
void Update()
{
// Use moveInput for movement
Vector3 movement = new Vector3(moveInput.x, 0f, moveInput.y);
transform.Translate(movement * 5f * Time.deltaTime);
}
}
Hook up the Events: Back in the Unity Editor, on your PlayerInput component, expand the "Events" foldout, and then your "Gameplay" Action Map. You'll see your "Move" and "Jump" actions. For each one, click the "+" button, drag your player GameObject into the object field, and select the corresponding method from your PlayerController script (e.g., PlayerController.OnMove).[15][16]
Method 2: Generating a C# Class
For more control and less reliance on the inspector, you can generate a C# class directly from your Input Action Asset. This creates a wrapper class that makes it easy to access your actions and their events in code.
Generate the Class: Select your "PlayerControls" asset in the Project window. In the Inspector, check the "Generate C# Class" box and click "Apply".[11][17] This creates a script with the same name as your asset.
Scripting with the Class: Now, you can use this class in your PlayerController script.
codeC#
using UnityEngine;
using UnityEngine.InputSystem;
public class PlayerController : MonoBehaviour
{
private PlayerControls playerControls;
private Vector2 moveInput;
private void Awake()
{
playerControls = new PlayerControls();
}
private void OnEnable()
{
playerControls.Gameplay.Enable();
playerControls.Gameplay.Jump.performed += DoJump;
}
private void OnDisable()
{
playerControls.Gameplay.Disable();
playerControls.Gameplay.Jump.performed -= DoJump;
}
private void DoJump(InputAction.CallbackContext context)
{
Debug.Log("Jump action was performed via C# event!");
// Add your jump logic here
}
void Update()
{
moveInput = playerControls.Gameplay.Move.ReadValue<Vector2>();
Vector3 movement = new Vector3(moveInput.x, 0f, moveInput.y);
transform.Translate(movement * 5f * Time.deltaTime);
}
}
In this approach, we create an instance of our PlayerControls class. In OnEnable, we enable the "Gameplay" Action Map and subscribe our DoJump method to the performed event of the "Jump" action. It's crucial to disable the action map and unsubscribe from the event in OnDisable to prevent memory leaks.[9][14] For the continuous movement input, we simply read the value directly in the Update loop.[14]
Handling Different Devices
One of the biggest strengths of the new Input System is its seamless handling of multiple devices.[13] Because we set up bindings for both keyboard and gamepad, the system automatically detects which device is being used and triggers the appropriate action.[13] You don't need to write any specific code to check which device is active. This makes creating cross-platform games significantly easier. The system supports a wide range of devices, including Xbox and PlayStation controllers, joysticks, and touchscreens.[18][19]
Switching Action Maps for Different Game States
As mentioned earlier, Action Maps are perfect for managing different control schemes. Imagine your game has a pause menu. You wouldn't want the player to keep moving in the background. By creating a "UI" Action Map with actions for navigation, you can switch to it when the game is paused.
Here's a conceptual example of how to switch between "Gameplay" and "UI" action maps:
codeC#
// In your script holding the PlayerControls instance
public void PauseGame()
{
playerControls.Gameplay.Disable();
playerControls.UI.Enable();
}
public void ResumeGame()
{
playerControls.UI.Disable();
playerControls.Gameplay.Enable();
}
By enabling and disabling the appropriate maps, you ensure that only the relevant controls are active at any given time, creating a much cleaner and more robust input architecture.[8][9][20]
This tutorial has covered the fundamentals of Unity's new Input System, from installation to scripting robust, multi-device player controls. While it might seem complex at first, its modular and event-driven nature provides a powerful foundation for any game, simplifying development for a multi-platform world.
Comments
Post a Comment