Unity

[Unity] InputSystem을 사용하여 이동하는 4가지 방식

게임 프로그래머 2025. 5. 28. 03:15

InputSystem 4가지 옵션

옵션  설명
Send Messages 현재 GameObject에 'On + Action name' 인 함수를 찾아서 호출하는 방식.
Broadcast Messages 현재 GameObject와 그 자식들까지 'On + Action name' 인 함수를 모두 호출
Invoke Unity Events UnityEvent로 연결, Inspector 상에서 Action에 함수를 설정하고 키 입력이 들어오면 호출
Invoke C# Events C# 스크립트에서 구독
키 입력 받고 실행 전, 실행 후, 키 입력 해제 등의 상황에 따라 별도의 함수 등록할 수 있다.

 

아래 언급되는 내용은 Broadcast Messages를 제외한 내용이 기재되었습니다.

Broadcast Messages은 자식 오브젝트의 메서드까지 모두 호출되므로 사용을 권장하지 않습니다.

공통 준비 사항

  1. Input Action Asset 설정
    • Move 액션 추가 (Type: Value, Control Type: Vector2)
    • WASD, 방향키 바인딩
  2. PlayerInput 컴포넌트 추가
    • Actions에 InputAsset 할당
    • Behavior를 각 방식별로 변경
  3. Rigidbody2D 컴포넌트 추가
    • Gravity Scale: 0
    • Constraints > Freeze Rotation: Z 체크

 

① Send Message

using UnityEngine;
using UnityEngine.InputSystem;

public class Player_SendMessage : MonoBehaviour
{
    public float moveSpeed = 5f;
    private Vector2 moveInput;
    private Rigidbody2D rb;

    void Awake()
    {
        rb = GetComponent<Rigidbody2D>();
    }

    void OnMove(InputValue value)
    {
    	moveInput = value.Get<Vector2>();
        // 아래는 3D
    	// Vector2 Input = value.Get<Vector2>();
        // moveInput = new Vector3(Input.x, 0, Input.y); 또는 그냥 moveInput = value.Get<Vector3>();
        // 단 Vector3로 받는경우 게임에 따라 바인딩 제거(위, 아래)
    }

    void FixedUpdate()
    {
        rb.velocity = moveInput * moveSpeed;
    }
}

 

PlayerInput의 Behavior를 Send Messages로 설정해야 동작함

 

② Invoke Unity Event 

using UnityEngine;
using UnityEngine.InputSystem;

public class Player_UnityEvent : MonoBehaviour
{
    public float moveSpeed = 5f;
    private Vector2 moveInput;
    private Rigidbody2D rb;

    void Awake()
    {
        rb = GetComponent<Rigidbody2D>();
    }
     
    // PlayerInput의 이벤트에서 Move 액션을 이 함수에 연결 (인스펙터에서)
    public void OnMove(InputAction.CallbackContext context)
    {
        moveInput = context.ReadValue<Vector2>();
    }

    void FixedUpdate()
    {
        rb.velocity = moveInput * moveSpeed;
    }
}

 

또는 조건(Started, Performed, Canceld 등)에 따라 나뉠수도 있음

using UnityEngine;
using UnityEngine.InputSystem;

public class Player_UnityEvent : MonoBehaviour
{
    public float moveSpeed = 5f;
    private Vector2 moveInput;
    private Rigidbody _rigidbody;

    void Awake()
    {
        _rigidbody = GetComponent<Rigidbody>();
    }  

    void Move()
    {
        Vector3 dir = transform.forward * moveInput.y + transform.right * moveInput.x;
        dir *= moveSpeed;
        dir.y = _rigidbody.velocity.y;
        
        _rigidbody.velocity = dir;
    }

    // 또는 조건에 따라 설정할 수도 있음
    public void OnMove(InputAction.CallbackContext context)
    {
        if (context.phase == InputActionPhase.Performed)
        {
            moveInput = context.ReadValue<Vector2>();
        }
        else if (context.phase == InputActionPhase.Canceled)
        {
            moveInput = Vector2.zero;
        }
    }

    void FixedUpdate()
    {
        Move();
    }
}

입력 조건(Started, Performed, Canceld 등)에 따라 로직을 달리할 수 있음 

 

PlayerInput의 Behavior를 Invoke Unity Events로 설정하고, Move 이벤트에 함수(OnMove) 연결

외부에서 연결해야 하므로 OnMove 메서드 접근제한자는 Public으로 설정

해당 스크립트 오브젝트를 담아주고 메서드를 연결

 

 

③ Invoke C# Event (InputActionReference 방식)

using UnityEngine;
using UnityEngine.InputSystem;

public class Player_CSharpEvent : MonoBehaviour
{
    public InputActionReference moveAction;  // InputActions -> Move 액션 drag
    public float moveSpeed = 5f;

    private Vector2 moveInput;
    private Rigidbody2D rb;

    void Awake()
    {
        rb = GetComponent<Rigidbody2D>();
    }

    void OnEnable()
    {
        moveAction.action.Enable(); // 입력 활성화
        moveAction.action.performed += OnMove;  // 입력 시작
        moveAction.action.canceled += OnMove; // 입력 종료 (0,0으로)
    }

    void OnDisable()
    {
        moveAction.action.Disable();
        moveAction.action.performed -= OnMove;
        moveAction.action.canceled -= OnMove;
    }

    private void OnMove(InputAction.CallbackContext context)
    {
        moveInput = context.ReadValue<Vector2>();
    }

    void FixedUpdate()
    {
        rb.velocity = moveInput * moveSpeed;
    }
}

InputActions -> Playe/Input을 할당해준다.

 

 

Invoke C# Event ( PlayerInputs 클래스 방식)

전체적으로 비슷하나 차이점이 존재한다.

  • Action Map으로의 접근을 위해 Action Map에 Player(이름은 자유, 이후 접근해야 함) 추가
  • InputAction 에셋을 선택하고 Inspector 상단 우측에 있는 [Generate C# Class] 체크
  • 이 방식은 PlayerInput 컴포넌트 필요 없음( 대신 PlayerInputs를 new로 생성해서 .Enable()로 수동 등록)

Generate 누르면 PlayerInputs.cs 생성된다.

[ActionMap과 동일한 이름(player) 문제 발생으로 인해 우측 사진은 PlayerInput으로 수정]

 

-------------------------- 일반 이벤트 연결 --------------------------
using UnityEngine;
using UnityEngine.InputSystem;

public class PlayerMove : MonoBehaviour
{
    private PlayerInput playerInput; // 자동 생성된 입력 클래스
    private Vector2 moveInput;         
    private Rigidbody2D rb;
    public float moveSpeed = 5f;

    void Awake()
    {
        rb = GetComponent<Rigidbody2D>();
        playerInputs = new PlayerInputs(); // 입력 시스템 인스턴스화
    }

    void OnEnable()
    {
        playerInputs.Enable();

        // 이벤트를 함수로 연결
        playerInputs.Player.Move.performed += OnMovePerformed;
        playerInputs.Player.Move.canceled += OnMoveCanceled;
    }

    void OnDisable()
    {
        // 이벤트 연결 해제
        playerInputs.Player.Move.performed -= OnMovePerformed;
        playerInputs.Player.Move.canceled -= OnMoveCanceled;

        playerInputs.Disable();
    }

    // 키가 눌렸을 때 실행
    private void OnMovePerformed(InputAction.CallbackContext context)
    {
        moveInput = context.ReadValue<Vector2>();
    }

    // 키가 떼졌을 때 실행
    private void OnMoveCanceled(InputAction.CallbackContext context)
    {
        moveInput = Vector2.zero;
    }

    void FixedUpdate()
    {
        rb.velocity = moveInput * moveSpeed;
    }
}