Unity Term Book
Scripting & Lifecycle

Input System

Input System package hiện đại của Unity — remap linh hoạt, hỗ trợ nhiều thiết bị, action theo sự kiện — thay thế hoàn toàn API polling Input.GetKey() cũ.

Hãy tưởng tượng...

Input System cũ = nhân viên phải liên tục gọi điện hỏi "Có khách chưa?" mỗi 0.016 giây (polling). Input System mới = lắp chuông cửa (event) — chỉ nhận thông báo khi có khách nhấn chuông. Ngoài ra, Action Maps giống bảng điều phối — cùng nút "Confirm" nhưng trong menu → Navigate Accept, trong game → Jump. Không cần viết if context == menu.

Khái niệm chi tiết

Input Actions Asset: file .inputactions cấu hình toàn bộ binding. Tổ chức theo Action Maps (Gameplay, UI, Vehicle…) → mỗi Map có các Actions (Move, Jump, Fire…) → mỗi Action có Bindings (phím, joystick, gamepad button…).

Event-driven: Subscribe vào action.started, action.performed, action.canceled. Gọi context.ReadValue<Vector2>() để lấy giá trị. Không cần polling trong Update.

Player Input component: Gắn vào GameObject → tự tạo Player Input component → subscribe events tự động. Hỗ trợ Message, C# Events, hoặc Unity Events.

Remapping tại runtime: action.AddBinding(), InputActionRebindingExtensions.PerformInteractiveRebinding() cho phép người chơi tự đổi keybind trong Settings menu.

Sơ đồ: 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)

Hướng dẫn thực hành

1

Cài Input System package

Window → Package Manager → Input System → Install. Khởi động lại khi được hỏi.

2

Tạo Input Actions Asset

Assets → Create → Input Actions. Thêm Action Maps, Actions, và Bindings cho từng phím/button.

3

Generate C# class

Chọn .inputactions file → Inspector → tick "Generate C# Class" → Apply → Unity tạo class wrapper.

4

Subscribe/Unsubscribe events

OnEnable: _actions.Gameplay.Jump.performed += OnJump; OnDisable: unsubscribe tương tự.

Trình mô phỏng tương tác

Nhấn các phím (hoặc click button bên dưới) và xem event được gọi đến đúng listener theo Action Map.

Active Map:

Virtual Input

Event Log

Nhấn phím để xem events...

Map: Gameplay|Events fired: 0

Ví dụ Code

Cơ bản

Dùng generated C# class với event subscription.

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);
}

Ví dụ Code

Nâng cao

Interactive Rebinding — cho phép người chơi đổi keybind tại 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);
              // Lưu binding string vào PlayerPrefs để persist
              PlayerPrefs.SetString("JumpBinding", jumpAction.action.SaveBindingOverridesAsJson());
          })
          .Start();
  }
}

📌 Ghi nhớ nhanh

  • Enable/Disable ActionMap theo context (Gameplay ↔ UI)
  • Subscribe trong OnEnable, Unsubscribe trong OnDisable
  • performed = phím/button được nhấn; canceled = thả
  • Generate C# class → gọn hơn, IntelliSense support

⚠️ Lỗi thường gặp

  • ❌ Quên Enable() Action Map

    Actions không kích hoạt dù đã subscribe — im lặng, không báo lỗi

    ✅ _actions.Gameplay.Enable() trong OnEnable

  • ❌ Quên Unsubscribe trong OnDisable

    Memory leak — event gọi vào object đã bị destroy

    ✅ Luôn mirror Subscribe/Unsubscribe theo OnEnable/OnDisable