| # Unity Input System |
|
|
| Unity offers two input systems: |
|
|
| 1. **Input Manager (legacy)** -- `Input.GetAxis`, `Input.GetKeyDown`. The |
| default in 2022.3 LTS. Used by every generated script in this project. |
| 2. **Input System package** -- the new event-driven API. Available via the |
| `com.unity.inputsystem` package. |
|
|
| ## Input Manager (legacy) |
|
|
| ### Axes |
|
|
| The legacy system reads virtual axes defined in |
| `Edit > Project Settings > Input Manager`. The defaults include: |
|
|
| | Axis name | Default keys | |
| |---------------|---------------------------------| |
| | `Horizontal` | A/D, Arrow Left/Right | |
| | `Vertical` | W/S, Arrow Up/Down | |
| | `Mouse X` | Mouse delta X | |
| | `Mouse Y` | Mouse delta Y | |
| | `Jump` | Space | |
| | `Fire1` | Left Ctrl / Mouse 0 | |
| | `Fire2` | Right Alt / Mouse 1 | |
| | `Fire3` | Left Shift / Mouse 2 | |
|
|
| ### Reading axes |
|
|
| ```csharp |
| float x = Input.GetAxisRaw("Horizontal"); // -1, 0, +1 (no smoothing) |
| float y = Input.GetAxis("Vertical"); // smoothed, -1..+1 |
| Vector2 move = new Vector2(x, y); |
| move = Vector2.ClampMagnitude(move, 1f); // prevent diagonal speed boost |
| ``` |
|
|
| * Use `GetAxisRaw` for responsive arcade movement; `GetAxis` for smooth |
| camera-style axes. |
| * Always clamp the magnitude of a 2-axis vector -- otherwise diagonal |
| movement is ~1.41x faster than cardinal. |
|
|
| ### Keys and buttons |
|
|
| ```csharp |
| if (Input.GetKeyDown(KeyCode.Space)) Jump(); |
| if (Input.GetKey(KeyCode.LeftShift)) Sprint(); |
| if (Input.GetKeyUp(KeyCode.E)) Interact(); |
| if (Input.GetMouseButtonDown(0)) Fire(); |
| if (Input.GetMouseButton(0)) FireContinuous(); |
| ``` |
|
|
| | Method | Fires when | |
| |-----------------------|-------------------------------------------| |
| | `GetKey` | Every frame the key is held | |
| | `GetKeyDown` | Only on the frame the key was pressed | |
| | `GetKeyUp` | Only on the frame the key was released | |
| | `GetMouseButton` | Every frame the button is held | |
| | `GetMouseButtonDown` | Only on the frame the button went down | |
|
|
| ### Mouse position and delta |
|
|
| ```csharp |
| Vector3 mousePos = Input.mousePosition; // screen-space pixels |
| float dx = Input.GetAxis("Mouse X"); // smoothed delta |
| float rawDx = Input.GetAxisRaw("Mouse X"); |
| ``` |
|
|
| To lock the cursor for first-person look: |
|
|
| ```csharp |
| Cursor.lockState = CursorLockMode.Locked; // hide + center |
| Cursor.visible = false; |
| ``` |
|
|
| ## Mouse-look recipe (first-person) |
|
|
| ```csharp |
| private float _pitch; |
| |
| private void Update() |
| { |
| float mx = Input.GetAxisRaw("Mouse X") * sensitivity; |
| float my = Input.GetAxisRaw("Mouse Y") * sensitivity; |
| |
| transform.Rotate(Vector3.up * mx); |
| _pitch = Mathf.Clamp(_pitch - my, -85f, 85f); |
| cameraTransform.localRotation = Quaternion.Euler(_pitch, 0f, 0f); |
| } |
| ``` |
|
|
| ## Mouse-look recipe (third-person orbit) |
|
|
| For a third-person camera we accumulate a **yaw** and **pitch** and build a |
| rotation each frame: |
|
|
| ```csharp |
| _yaw += Input.GetAxis("Mouse X") * sensitivity; |
| _pitch -= Input.GetAxis("Mouse Y") * sensitivity; |
| _pitch = Mathf.Clamp(_pitch, -30f, 75f); |
| Quaternion rotation = Quaternion.Euler(_pitch, _yaw, 0f); |
| Vector3 position = pivot + rotation * new Vector3(0f, height, -distance); |
| ``` |
|
|
| The `ThirdPersonCamera.cs` generator follows exactly this pattern. |
|
|
| ## Input System package (new) |
|
|
| When the project has the Input System package active, the legacy `Input` |
| class will throw or return zeros unless `Project Settings > Player > Active Input Handling = Both`. |
|
|
| The new API is event-based: |
|
|
| ```csharp |
| [SerializeField] private InputActionAsset actions; |
| private InputAction _moveAction; |
| |
| private void OnEnable() |
| { |
| _moveAction = actions.FindAction("Move"); |
| _moveAction.performed += OnMove; |
| _moveAction.Enable(); |
| } |
| |
| private void OnMove(InputAction.CallbackContext ctx) => _moveInput = ctx.ReadValue<Vector2>(); |
| private void OnDisable() => _moveAction.Disable(); |
| ``` |
|
|
| For the generated project we keep Active Input Handling on **Both** so the |
| legacy `Input` calls in the generated scripts keep working. |
|
|
| ## Touch and mobile |
|
|
| For mobile, read `Input.touches` (legacy) or the new Input System's |
| `Pointer`/`Touchscreen`: |
|
|
| ```csharp |
| foreach (Touch t in Input.touches) |
| { |
| if (t.phase == TouchPhase.Began) HandleTap(t.position); |
| } |
| ``` |
|
|
| The generated scripts are desktop-first; you would add a virtual joystick |
| overlay for mobile ports. |
|
|
| ## Common pitfalls |
|
|
| * Reading `Input` in `FixedUpdate` -- the input system updates once per |
| frame, but `FixedUpdate` may run 0..N times per frame, so you will drop |
| or duplicate inputs. |
| * Using `Input.GetAxis` for physics forces -- the smoothed value can cause |
| floaty controls. Prefer `GetAxisRaw` and apply your own smoothing. |
| * Forgetting to lock the cursor in an FPS leads to the camera spinning |
| when the cursor leaves the game window. |
|
|