Unity Term Book
스크립팅 & 라이프사이클

Input System

Input System은 레거시 Input.GetKey 폴링을 대체하는 최신 패키지로 리맵·멀티 디바이스·이벤트 기반 Action을 지원합니다. Action Maps·Bindings·C# 클래스 생성·OnEnable 구독과 리바인딩을 다룹니다. 핵심 개념과 실습을 함께 익힙니다.

상상해 보세요...

구 Input System은 직원이 0.016초마다 전화해 "손님 왔나요?"라고 묻는 방식(폴링)입니다. 신 Input System초인종(이벤트)을 달아——눌릴 때만 들립니다. Action Maps는 배정 보드처럼——같은 "Confirm"이 메뉴에선 Navigate Accept, 게임플레이에선 Jump입니다. `if (context == menu)` 스파게티가 없습니다.

개념 자세히

Input Actions Asset은 모든 바인딩을 담는 .inputactions 파일입니다. 구조는 Action Maps(Gameplay, UI, Vehicle…) → 각 Map에 Actions(Move, Jump, Fire…) → 각 Action에 Bindings(키, 스틱, 게임패드 버튼…).

이벤트 기반: action.started, action.performed, action.canceled에 구독합니다. 값은 context.ReadValue<Vector2>()로 읽습니다. Update 폴링이 필요 없습니다.

Player Input 컴포넌트: GameObject에 붙여 이벤트를 자동으로 연결합니다. Messages, C# Events, Unity Events를 지원합니다.

런타임 리맵: action.AddBinding()InputActionRebindingExtensions.PerformInteractiveRebinding()으로 Settings 메뉴에서 키바인드를 바꿀 수 있습니다.

다이어그램: Input System 아키텍처

⌨️ 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)

실습 단계

1

Input System 패키지 설치

Window → Package Manager → Input System → Install. 안내가 나오면 재시작.

2

Input Actions Asset 만들기

Assets → Create → Input Actions. Action Maps·Actions·키/버튼별 Bindings를 추가합니다.

3

C# 클래스 생성

.inputactions 선택 → Inspector → "Generate C# Class" 체크 → Apply → Unity가 래퍼 클래스를 만듭니다.

4

이벤트 구독 / 해제

OnEnable: _actions.Gameplay.Jump.performed += OnJump; OnDisable: 같은 방식으로 해제.

인터랙티브 시뮬레이터

키(또는 아래 버튼)를 누르고 활성 Action Map의 올바른 리스너로 이벤트가 가는 모습을 보세요.

Active Map:

Virtual Input

Event Log

키를 눌러 이벤트를 보세요...

Map: Gameplay|Events fired: 0

코드 예제

기본

생성된 C# 클래스와 이벤트 구독을 사용합니다.

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

코드 예제

고급

인터랙티브 리바인딩——플레이어가 런타임에 키바인드를 바꿉니다.

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);
              // Persist binding overrides
              PlayerPrefs.SetString("JumpBinding", jumpAction.action.SaveBindingOverridesAsJson());
          })
          .Start();
  }
}

📌 빠른 정리

  • 컨텍스트에 따라 ActionMaps Enable/Disable (Gameplay ↔ UI)
  • OnEnable에서 구독, OnDisable에서 해제
  • performed = 누름; canceled = 뗌
  • C# 클래스 생성 → 더 깔끔한 API + IntelliSense

⚠️ 흔한 실수

  • ❌ Action Map에 Enable() 잊음

    구독해도 Action이 안 불림——조용한 실패

    ✅ OnEnable에서 _actions.Gameplay.Enable()

  • ❌ OnDisable에서 Unsubscribe 잊음

    메모리 누수——파괴된 객체로 이벤트 호출

    ✅ OnEnable/OnDisable로 Subscribe/Unsubscribe를 항상 대칭