본문 바로가기
Unity

Input Sytem : InputAction 사용법 정리

by Oz Driver 2025. 7. 14.

InputAction 의 세 가지 이벤트

Unity의 새로운 Input System에서 InputAction은 아래 세 가지 주요 이벤트를 제공합니다

 

•   started : 키를 누르기 시작한 순간 호출됨. 키가 눌렸다는 의지를 감지한 시점으로, 실제 입력값이 0일 수도 있음

•   performed : 입력이 의미 있는 값으로 들어왔을 때 호출됨. 보통 키가 완전히 눌렸을 때, 혹은 스틱이 어느 정도 이상 움직였을 때 발생

•   canceled : 입력이 취소되었을 때 호출됨 (예: 키를 뗀 순간, 스틱을 원점으로 되돌린 경우 등)

 

일반 키보드에서는 started 이후 거의 동시에 performed 로 이어지지만, 스틱처럼 아날로그 장치에서는 미묘한 차이가 발생합니다. 따라서 만약 키보드만 다룬다면 둘 간의 구분은 거의 무의미합니다.

[SerializeField] 
private InputAction rotateAction;

private void OnEnable()
{
    // 이벤트 함수 등록 
    rotateAction.started += OnRotateStarted;
    rotateAction.performed += OnRotatePerformed;
    rotateAction.canceled += OnRotateCanceled;
    
    // InputAction 활성화
    rotateAction.Enable();
}

private void OnDisable()
{
    // InputAction 비활성화
    rotateAction.Disable();
}

private void OnRotateStarted(InputAction.CallbackContext context)
{
    // 최초 1회만 호출됨
    if (context.started)
        Debug.Log("Rotate started");
}

private void OnRotatePerformed(InputAction.CallbackContext context)
{
    // 최초 1회만 호출됨
    if (context.performed)
        Debug.Log("Rotate performed");
}

private void OnRotateCanceled(InputAction.CallbackContext context)
{
    // 최초 1회만 호출됨
    if (context.canceled)
        Debug.Log("Rotate canceled");
}

 

위 방식은 Player Input 컴포너트를 사용하지 않고 직접 코드로 제어하는 방식입니다.

먼저, InputAction 을 [SerializedField] 로 직렬화한 후, 유니티 Inspector 창에서 적절한 입력을 Binding 시키면 해당 입력의 상태에 따라 이벤트가 호출되는 구조입니다. 또한 사용자가 직접 이벤트를 등록하고, 활성 / 비활성 처리를 해주어야 합니다. 이 때 각 이벤트는 최초 1회호출됩니다. 따라서 키가 "계속 눌리는 동안" 에 대한 이벤트를 받고 싶을 때는 별도의 처리를 해야 합니다. 

 

지속적인 입력 (Pressed 상태) 처리 방법 

키가 눌렸는지에 대한 처리는 IsPressed() 함수로 간단히 체크할 수 있습니다.

[SerializeField]
InputAction trustAction;
    
void OnEnable()
{   
    trustAction.Enable();
}
   
void OnDisable()
{
    trustAction.Disable();
}

private void Update()
{
    // trustAction 에 매핑된 입력이 눌리고 있는 동안은 "참"
    if (trustAction.IsPressed())
    {
        Debug.Log("Trust action Pressed");
    }
}

 

입력 값 처리 방법 

입력 값은 ReadValue<T>() 함수를 사용합니다. 

이 때 <T> 값은 유니티 Inspector 창에서 어떤 값으로 binding 했는지에 따라 달라집니다. 

 

  AddBinding

 - 단순한 버튼 입력 등에 사용되며, 별도의 값 없이 이벤트 발생 여부만 감지합니다. 

   Add Positive / Negative Binding

 - float 으로 값을 저장합니다. 

   Add Up / Down / Left / Right 

 - Vector2 로 값을 저장합니다. 

 

만약, Binding 된 상태와 코드에서 읽어오는 타입이 다르다면, 런타임 에러가 발생하기 때문에 주의가 필요합니다. 

다음은 Binding 된 입력의 상태와 값을 처리하는 전 코드입니다. ( 이벤트 등록, 해제 및 콜백 함수 포함 )

using UnityEngine;
using UnityEngine.InputSystem;

public class Movement : MonoBehaviour
{
    [SerializeField]
    InputAction trustAction;

    [SerializeField]
    InputAction rotateAction;

    [SerializeField]
    private float trustStrength = 1000.0f;

    [SerializeField]
    private float rotateSpeed = 30.0f;

    private Rigidbody rb;    
   
    void OnEnable()
    {   
        // trust 이벤트 등록
        trustAction.started += OnTrustStarted;
        trustAction.performed += OnTrustPerformed;
        trustAction.canceled += OnTrustCanceled;
        
        // rotate 이벤트 등록
        rotateAction.started += OnRotateStarted;
        rotateAction.performed += OnRotatePerformed;
        rotateAction.canceled += OnRotateCanceled;
        
        trustAction.Enable();
        rotateAction.Enable();
    }
   
    void OnDisable()
    {
        // trust 이벤트 해제
        trustAction.started -= OnTrustStarted;
        trustAction.performed -= OnTrustPerformed;
        trustAction.canceled -= OnTrustCanceled;
        
        // rotate 이벤트 해제
        rotateAction.started -= OnRotateStarted;
        rotateAction.performed -= OnRotatePerformed;
        rotateAction.canceled -= OnRotateCanceled;
        
        trustAction.Disable();
        rotateAction.Disable();
    }

    private void Start()
    {
        rb = GetComponent<Rigidbody>();
        if (rb == null)
        {
            Debug.LogError("Rigidbody component is missing");
        }
    }

    private void Update()
    {
        ProcessInput();
    }

    private void ProcessInput()
    {
        if (trustAction.IsPressed())
        {
            rb.AddForce( transform.up * ( trustStrength * Time.deltaTime ) );
            Debug.Log("Trust action Pressed");
        }

        if (rotateAction.IsPressed())
        {
            float inputValue = rotateAction.ReadValue<float>();
            inputValue *= -1.0f;
            transform.Rotate(Vector3.forward, inputValue * rotateSpeed * Time.deltaTime);
            Debug.Log($"Rotate action Pressed : {inputValue}");
        }
    }
    
    // Trust Event Callback 함수
    private void OnTrustStarted(InputAction.CallbackContext context)
    {
        Debug.Log("Trust started");
    }

    private void OnTrustPerformed(InputAction.CallbackContext context)
    {
        Debug.Log("Trust performed");
    }

    private void OnTrustCanceled(InputAction.CallbackContext context)
    {
        Debug.Log("Trust canceled");
    }
        
    // Rotate Event Callback 함수    
    private void OnRotateStarted(InputAction.CallbackContext context)
    {
        Debug.Log("Rotate started");
    }

    private void OnRotatePerformed(InputAction.CallbackContext context)
    {
        Debug.Log("Rotate performed");
    }

    private void OnRotateCanceled(InputAction.CallbackContext context)
    {
        Debug.Log("Rotate canceled");
    }    
}

 

정리

•   순간 입력 (점프, 클릭) 은 performed 이벤트에서 처리합니다.

•  지속 입력 (이동, 조준) 은 IsPressed() 함수를 사용합니다. 

•  입력 값이 필요한 경우라면 ReadValue<T>() 함수를 사용합니다. 

•   ReadValue<T>() 함수는 바인딩 방식에 따라 정확한 타입 (float, Vector2 등) 으로 읽어야 합니다.

 

Unity의 InputAction은 다양한 입력 상황을 유연하게 처리할 수 있도록 설계되어 있으며, 이벤트 기반 처리와 상태 기반 처리를 함께 조합하면 보다 안정적이고 직관적인 입력 로직을 만들 수 있습니다.