내일배움캠프/TIL

내일배움캠프 22일차 TIL - Input System 특강 정리

서보훈 2024. 10. 16. 21:14

Input System 은 기존 Input Manager를 대체하는 시스템으로 사실상 기존 Input Manager 가 레거시 시스템이라고 볼 수 있습니다.

 

다이렉트 방식, 임베디드 방식, 액션 에셋 방식, C# 제너레이트 방식 4종류의 방법으로 사용할 수 있습니다.

 

입력을 받는 스크립트는 UnityEngine.InputSystem 을 사용해야 합니다.

using UnityEngine;
using UnityEngine.InputSystem;

public class InputSystemTest : MonoBehaviour
{
    
}

 


다이렉트 방식

InputSystem 에서 지원하는 입력방식의 클래스를 변수로 선언하고, 변수를 통해 직접 입력받는 시스템 방식 입니다.

이때, 클래스 변수에는 Keyboard.current 를 사용하여 현재 사용중인 키보드를 지정해 줄 수 있습니다.

public class InputSystemTest : MonoBehaviour
{
    private Keyboard mainKeyboard;
    private Mouse mainMouse;

    private void Start()
    {
        mainKeyboard = Keyboard.current;
        mainMouse = Mouse.current;
    }
}

 

사용은 Input Manager와 비슷합니다.

키보드에는 aKey, sKey 등의 방식으로 키보드 자판이 지정되어 있으며, 마우스는 leftButton 등의 형태입니다.

게임패드등에도 지정하는 값에 맞추어 사용해주면 됩니다.

private void Update()
{
    if (mainKeyboard.aKey.isPressed)
    {
        Debug.Log("A 키 입력중");
    }

    if(mainMouse.leftButton.wasPressedThisFrame)
    {
        Debug.Log("좌클릭 입력");
    }

    if(mainKeyboard.sKey.wasReleasedThisFrame)
    {
        Debug.Log("S 키 뗌");
    }
}

입력방식은 isPressed, wasPressedThisFrame, wasReleasedThisFrame 으로 나누어져 있습니다.

isPressed 누르는 동안 true 반환
wasPressedThisFrame 누른 프레임에서만 true 반환
wasReleasedThisFrame 떼는 프레임에서만 true 반환

 

상황에 맞추어 사용할 수 있으며, 임시로 빠르게 조작 시스템을 만들 때 사용하기 좋다고 합니다.

 

※ 개인적인 견해로는 키보드, 게임패드등 여러 조작법을 지원할경우 조작방식에 따라 입력값을 추가로 제작해야하기 때문에 확실히 주로 쓰기에는 좋지 않아보입니다.

 


임베디드 방식

Input System 에서는 InputAction 을통해 입력을 받아서 사용할 수 있습니다.

이 InputAction 을 스크립트에서 직접 선언하여 사용하는 방식입니다.

public class InputSystemTest : MonoBehaviour
{
    public InputAction input;
}

 

public 으로 InputAction 클래스 변수를 선언하면, 선언해준 변수명으로 우측 아래와 같이 바인딩을 넣을 수 있는 공간이 생성됩니다.

 

+ 를 눌러서 어떤 입력을 받을지 선택하는 바인딩을 추가하여 사용합니다.

바인딩은 입력을 받는 기준으로, positive, negative 의 경우 2개의 입력값을 받아 하나의 버튼에는 -1, 다른 쪽에는 1의 값을 출력하도록 만들어줍니다.

바인딩을 만들어주면, 바인딩을 클릭하는것으로 해당 바인딩에 어떤 값을 넣어줄것인지 선택할 수 있습니다.

임베디드 방식은 이벤트로 기동하며, Update문을 사용하지 않습니다.

이에따라 성능에 이점이 존재합니다.

 

임베디드 방식 사용시, InputAction 으로 선언한 변수는 이벤트의  역할을 하며 이에따라 작동할 함수를 이벤트에 등록해주어야 합니다.

또한, .Enable을 사용하여 InputAction을 활성화 해줄 필요가 있습니다.

이러한 작업은 컴포넌트가 활성화, 비활성화 될 때 작동하는 OnEnable(), OnDisable() 에서 처리해주는것이 좋습니다.

public class InputSystemTest : MonoBehaviour
{
    public InputAction input;

    public float inputValue;

    private void OnEnable()
    {
        input.performed += MoveInput;
        input.canceled += StopInput;

        input.Enable();
    }

    private void OnDisable()
    {
        input.performed -= MoveInput;
        input.canceled -= StopInput;

        input.Disable();
    }

    private void MoveInput(InputAction.CallbackContext value)
    {
        inputValue = value.ReadValue<float>();
        Debug.Log($"입력중 : {inputValue}");
    }

    private void StopInput(InputAction.CallbackContext value)
    {
        inputValue = value.ReadValue<float>();
        Debug.Log($"입력 종료 : {inputValue}");
    }
}

위와 같은 코드 사용시, A 입력시 -1 출력, D 입력시 1 을 출력하고 뗄 때 0을 출력하게 됩니다.

 

이 경우, 스크립트에 직접 입력을 지정하기 때문에 스크립트마다 다른 입력을 받을 수 있는 장점이 있습니다.

단, 스크립트 마다 개별적으로 바인딩 작업을 해줘야하며, 개별적으로 이벤트를 등록해주어야하는 단점이 있습니다.


액션 에셋 방식

InputSystem 에는 InputAction 을 생성할 수 있습니다.

이렇게 생성한 InputAction을 통해 입력을 받는것이 액션 에셋 방식이며, Input System 의 기본이 됩니다.

 

해당 에셋을 더블클릭하면, 이러한 창이 나옵니다.

여기에 ActionMap 과 바인딩을 지정해준 뒤, 사용하게 됩니다.

 

먼저 Scheme 을 생성하여 입력 방식을 선택해줍니다.

이후 Action Maps 의 우측 + 를 눌러서 액션맵을 만들어주고, 바인딩을 추가해줍니다.

Actions의 값을 우클릭해서 바인딩을 정해줄 수 있으며, 우측 Action Type에 따라서 만들수 있는 바인딩이 달라집니다.

또한 Actions 의 이름은 Send Message 방식을 사용할 때, 중요하게 사용됩니다.

임베디드 방식과 비슷한 형식으로 만들어주었습니다.

이후, 상단의 Save Asset 을 눌러줘야 저장됩니다.

 

이후, 해당 InputAction 을 사용할 오브젝트에 Player Input 컴포넌트를 붙입니다.

이후, Actions 에 만들어준 에셋을 올려줍니다.

 

Default Scheme 에서 만들어준 Scheme 중 사용할 것을 지정해 줄 수 있으며, Default Map 에서 어떤 ActionMap 을 사용할지 결정할 수 있습니다.

Behavior 를 통해 작동방식을 선택할 수 있는데, Send Messages 와 Invoke Unity Events 2종류만 설명하겠습니다.

 

Send Messages

Send Messages 방식은 Actions 에 등록한 이름 앞에 On 이 붙은 함수를 호출합니다.

Move 라는 액션을 만들어주었기 때문에, OnMove() 함수를 호출하며, 이때 매개변수로 InputValue를 가지고 있어야합니다.

public class InputSystemTest : MonoBehaviour
{
    public float input;

    private void OnMove(InputValue value)
    {
        input = value.Get<float>();
    }
}

입력한 값은 value 값을 통해 반환받으며, button의 경우 value.isPressed 를 통해 true,false 값을 전달받고, 2개의 바인딩이 있는 이번 값은 value.Get<float>() 를 통해 -1 ~ 1 값을 받을 수 있습니다.

 

※Broadcast Message 또한 작동방식이 같으며, 차이점은 Send Messages는 자신과 같은 오브젝트에만, Broadcast Message는 자식 오브젝트까지 이벤트함수를 작동시킵니다.

 

Invoke Unity Events

이 방식은 함수의 이름은 상관이 없으며, 버튼과 유사하게 선언한 함수를 등록하여 사용하는 방식입니다.

또한 함수의 매개변수로 InputAction.CallbackContext 를 사용하게 됩니다.

public class InputSystemTest : MonoBehaviour
{
    public float input;

    public void OnMove(InputAction.CallbackContext value)
    {
        input = value.ReadValue<float>();
        Debug.Log($"입력중 : {input}");
    }
}

이 함수를 Player Input 컴포넌트에 등록해야합니다.

Behavior 를 변경하면 아래에 등록을 위한 공간이 생기며, 만들어준 ActionMap 인 Player 를 펼쳐보면 Action 호출시 작동할 함수를 등록할 수 있습니다.

 

 

이 외에도 코드상에서 직접 사용하는 방법이 존재합니다.

InputActionAsset 을 변수로 선언한 뒤, 만들어준 Input Acion을 등록해주어 사용하면 됩니다.

public class InputSystemTest : MonoBehaviour
{
    public InputActionAsset inputAction;

    public InputActionMap player;
    public InputAction moveAction;

    public float input;

    private void OnEnable()
    {
        player = inputAction.FindActionMap("Player");
        moveAction = inputAction.FindAction("Move");

        moveAction.performed += PlayerMove;

        player.Enable();
    }

    private void OnDisable()
    {
        player.Disable();
    }

    private void PlayerMove(InputAction.CallbackContext value)
    {
        input = value.ReadValue<float>();
    }
}

 

 

이때 OnEnable에서 ActionMap 과 Action 을 등록해주어야합니다.

또한 이경우 작동할 Action 에 .performed, .canceled 에 이벤트를 등록해주어야 하며,

각각 누르는중, 떼기를 당담합니다.

 


C# 제너레이트 방식

C# 제너레이트 방식은 InputAction을 스크립트로 만든뒤, 그 스크립트를 사용하는방식입니다.

만들어준 Input Action Asset 을 선택하고 인스펙터 창을 보면 Generate C# Class 가 존재하는데, 이를 체크한 뒤 Apply 를 눌러서 스크립트를 만들어줍니다.

 

스크립트가 만들어지면, 움직일 오브젝트에 해당 스크립트의 객체를 새로 만들어주면 사용할 준비가 끝납니다.

public class InputSystemTest : MonoBehaviour
{
    private InputTest inputTest;

    private float input;

    private void OnEnable()
    {
        inputTest = new InputTest();

        inputTest.Player.Move.performed += PlayerMove;

        inputTest.Enable();
    }

    private void OnDisable()
    {
        inputTest.Player.Move.performed -= PlayerMove;

        inputTest.Disable();
    }

    private void PlayerMove(InputAction.CallbackContext value)
    {
        input = value.ReadValue<float>();
    }
}

 

OnEnable, OnDisable 에서 켜고, 꺼줘야하며 이벤트를 등록해주어야 할 필요가 있지만, 만들어준 Action 등이 생성된 클래스에 구현되어있는 상태이기 때문에 값을 잘못 입력하여 작동하지 않을 가능성이 크게 줄어듭니다.

 

EventSystem과 InputActionAsset 의 세부 설정은 이후 정리하겠습니다.