신형 Unity Input System을 C# 이벤트(delegate) 방식으로 처리하고,
이를 통해 입력과 로직을 완전히 분리하는 구조를 구현한다.
Unity의 Input System은 대표적으로 두 가지 방식으로 입력을 처리할 수 있다.
UnityEvent
인스펙터에서 버튼처럼 함수 할당
빠르게 테스트하거나 단순한 UI 입력 처리에 적합
C# 이벤트(delegate)
코드에서 직접 델리게이트를 통해 콜백 연결
구조화, 테스트, 입력 분리에 유리 (대부분의 플레이어 컨트롤에 적합)
이번에는 C# 이벤트 방식으로 구현하는 흐름을 정리해본다.
PlayerInput 설정
PlayerInput 컴포넌트를 오브젝트에 붙이고
Behavior: Invoke C# Events로 설정한다.
public class PlayerController : MonoBehaviour
{
private PlayerInputs input;
private PlayerInputs.PlayerActions actions;
private void Awake()
{
input = new PlayerInputs();
actions = input.Player;
}
private void OnEnable()
{
input.Enable();
RegisterInputCallbacks();
}
private void OnDisable()
{
UnregisterInputCallbacks();
input.Disable();
}
private void RegisterInputCallbacks()
{
actions.Movement.performed += OnMove;
actions.Movement.canceled += OnMoveCanceled;
actions.Jump.started += OnJumpStarted;
actions.Jump.canceled += OnJumpCanceled;
}
private void UnregisterInputCallbacks()
{
actions.Movement.performed -= OnMove;
actions.Movement.canceled -= OnMoveCanceled;
actions.Jump.started -= OnJumpStarted;
actions.Jump.canceled -= OnJumpCanceled;
}
private void OnMove(InputAction.CallbackContext ctx)
{
Vector2 moveDir = ctx.ReadValue<Vector2>();
Debug.Log($"Move: {moveDir}");
}
private void OnMoveCanceled(InputAction.CallbackContext ctx)
{
Debug.Log("Move canceled");
}
private void OnJumpStarted(InputAction.CallbackContext ctx)
{
Debug.Log("Jump pressed");
}
private void OnJumpCanceled(InputAction.CallbackContext ctx)
{
Debug.Log("Jump released");
}
}
입력과 로직 분리 PlayerController, UI, 대화 시스템 등에서 각자 필요한 입력만 따로 받아 처리 가능
확장성 - 여러 오브젝트에서 동일 입력을 독립적으로 처리 (예: UI 열기 + 플레이어 정지)
유닛 테스트 친화적 - 코드로 입력 이벤트를 직접 발생시켜 테스트 가능
코드 가독성 향상 - 구조화된 이벤트 기반 처리로 추적이 쉬움
대형 프로젝트나 멀티 모듈 구조에서는 아래처럼 InputReader 클래스를 따로 두고
플레이어나 시스템들이 이 클래스를 구독하도록 만들면 의존성이 더 깔끔하게 분리된다.
public class InputReader : MonoBehaviour
{
private PlayerInputs inputs;
public event Action<Vector2> MoveEvent;
public event Action JumpEvent;
private void Awake()
{
inputs = new PlayerInputs();
inputs.Player.Movement.performed += ctx => MoveEvent?.Invoke(ctx.ReadValue<Vector2>());
inputs.Player.Jump.started += _ => JumpEvent?.Invoke();
}
private void OnEnable() => inputs.Enable();
private void OnDisable() => inputs.Disable();
}
이런 식으로 모듈화하면, 입력 자체를 완전히 외부로부터 분리할 수 있다.
예를 들어 플레이어는 단순히 MoveEvent만 구독하고, 입력 소스가 무엇인지는 몰라도 된다.
Unity Input System은 C# 이벤트 기반 구조로도 충분히 유연하고 확장 가능하게 사용할 수 있다.
PlayerInputs의 자동 생성 클래스와 PlayerInput 컴포넌트를 조합하면
명확한 입력 구조와 이벤트 흐름을 만들 수 있다.
복잡한 프로젝트일수록 입력 감지 → 입력 처리 로직을 분리하는 것이 유지보수에 큰 도움이 된다.