유니티2D 입문 정리 4 - Input System으로 입력 업그레이드

woollim·2024년 10월 8일
0

1. InputManager의 문제점

○ 조이스틱 등 다양한 입력 장비 대응

지금 현재 InputManager에서는 다양한 플랫폼에 대응하거나, 키를 변경하는 리바인딩하는 그런 부분이 부족함

○ 입력 처리와 실제 로직 실행 주체를 분리

  • 사실 InputManager 자체의 문제로 보기는 어렵지만, 해당 버전에서는 구현했던 내용들이 모두 한 클래스들에 모여있어 클래스에 대한 확장성과 유지보수성이 많이 떨어지는 문제가 있음

  • 기능별로 클래스를 나누는 것은 설계에 많은 도움을 줌
    -> 단일 책임 원칙(Single Responsibility Principle)

  • New Input System의 핵심 개념들

    1. Input Action : 입력 행동을 정의함.
      예를 들어 "점프", "공격" 등의 행동을 정의하고, 이러한 행동을 트리거하는 키 또는 버튼을 지정할 수 있음
    2. Input Action Asset : 여러 개의 입력 행동을 그룹화하는 방법. 이를 통해 재사용 가능한 입력 설정을 만들어 게임 내의 다른 캐릭터나 메뉴에 적용할 수 있음
    3. Player Input Component : Unity의 New Input System에 추가된 새로운 컴포넌트로, 자동으로 입력 행동을 처리하고 해당 게임 오브젝트에 메시지를 보냄
  • New Input System의 장점

    1. Cross-Platform Compatibility: New Input System은 다양한 플랫폼과 입력 장치에 대해 일관된 방식으로 작동함
    2. Rebinding: 플레이어가 게임 내에서 자신의 입력 설정을 변경할 수 있도록 지원함
    3. Multiplayer Support: 여러 플레이어가 동일한 장치에서 게임을 플레이하거나, 각각의 장치에서 게임을 플레이할 때 입력을 쉽게 처리할 수 있음



2. 입력 설계 실습

○ 설계하기

  1. 컨트롤러는 어떤 오브젝트의 상황에 따라 행동을 결정하고, 이를 TopDownMovement와 같이 실제 로직을 수행하는 컴포넌트들에 이벤트들을 전달하는 역할을 함

  2. 이러한 컨트롤러는 플레이어에만 들어가는 것이 아니므로, 이번에는 PlayerInputController를 만들겠지만,
    적에게도 사용되는 공통적 기능들은 TopDownController에 정의하여 이를 재활용할 수 있게 해야 함

  3. 이번 강의에서 TopDownController에서는
    이동과 관련된 액션들을 모두 실행하는 CallMoveEvent,
    마우스와 관련된 이벤트를 모두 실행하는 OnLookEvent를 정의하고 이를 호출하는 기능만 추가함
    - 움직이는 것, 조준하는 것 말고 오브젝트들이 가지는 다른 이벤트 -> 공격관련 이벤트

○ 입력 받을 준비하기

  1. Pakages : unity Registry -> input system 검색 -> install

  2. Package 추가하기

    • Window → Package Manager → Unity Register → Input System → Install

  3. New Input Sytem 준비하기

    • Create → Input Action 클릭 → Top Down Controller 2D로 수정
  1. Input System의 다양한 옵션들 배워두기

    • Action Type : 입력을 어떻게 받을 것인가
      • Value : 일반적인 상태에 사용함. 눌렀을 때, 누르고 있을 때, 뗄 때 등 다양한 상황에 대응할 수 있고, 다양한 컨트롤에 대응할 수 있음
      • Button : 눌렀을 때 딱 발생하는 액션에 활용. Control 타입이 Button으로 고정됨
      • Pass-Through : 명확화(Disambiguation)을 거치지 않은 Value. Value 쓰면됨
    • Control Type : 입력 데이터가 어떤 식으로 들어올 것인가
      - Axis(float), Button(일반적으론 버튼을 누름에 따라 1, 0, 하지만 특이 케이스 있음), Vector2 (조이스틱 같은 것에 활용)
  2. Input Action 수정하기

    • InputAction 더블클릭

    • No Control Schemes → Add Control Scheme

    • 이름 수정 → + 버튼 → Keyboard 와 Mouse 추가

      • Control Scheme이란? 액스박스 용이다, 컴퓨터 용이다 등 분류를 나누는 것
      • 🤷‍♂️!유니티 2022 버전 특유의 오류가 있음!
        이 오류는 일반적으로 Keyboard나 Mouse를 선택할 때 마우스 왼쪽으로 선택하는 것이 아니라 마우스🖱️ 오른쪽 👉🏻 클릭으로 선택하면 해결
    • Action Maps → + → Player

    • Actions → Move, Look, Fire 추가

      • Move / Look : Action Type Value Control Type Vector2
      • Fire : Action Type Value Control Type Any -> float 같은 느낌
    • 수정 → Add Up Down Left Right Composite 추가 → WASD 설정
      W/S/A/D를 합쳐서 Vector2를 만드는 것이기 때문에 특별한 바인딩 활용해야 함

    • Look Action 수정
      마우스 위치 하나가 Vector2를 만드는 것이기 때문에 그냥 수정만 하면 됨

    • Fire Action 수정


○ 플레이어 만들기

  • TopDownController 만들기
using System;
using UnityEngine;


public class TopDownController : MonoBehaviour
{
    public event Action<Vector2> OnMoveEvent; // Vector2를 인자로 받는 함수
    public event Action<Vector2> OnLookEvent; // Action은 무조건 void만 반환


    public void CallMoveEvent(Vector2 direction)
    {// move 이벤트가 발생했을 때 Invoke 하는 함수
        OnMoveEvent?.Invoke(direction); // ?. 없으면 말고, 있으면 실행한다
    }

    public void CallLookEvent(Vector2 direction)
    {
        OnLookEvent?.Invoke(direction);
    }
}
  • PlayerInputController 만들기
using UnityEngine;
using UnityEngine.InputSystem;

public class PlayerInputController : TopDownController
{
    private Camera _camera;
    private void Awake()
    {
        _camera = Camera.main; // 메인 카메라 라는 태그를 붙은 카메라를 가져온다
    }

    public void OnMove(InputValue value) // W input 값 같은 애들이 여기로 들어온다
    {
        // Debug.Log("OnMove" + value.ToString());
        Vector2 moveInput = value.Get<Vector2>().normalized;
        CallMoveEvent(moveInput); // TopDownController에서 상속 받아옴
        // 실제 움직이는 것은 여기서 하는 것이 아니라, PlayerMovement에서 함
    }

    public void OnLook(InputValue value) // W input 값 같은 애들이 여기로 들어온다
    {
        // Debug.Log("OnLook" + value.ToString());
        Vector2 newAim = value.Get<Vector2>(); // 마우스 위치 이기 떄문에 normalized 하면 안된다.
        Vector2 worldPos = _camera.ScreenToWorldPoint(newAim);
        newAim = (worldPos - (Vector2)transform.position).normalized;
        // transform.position 에서 월드가 어느 방향에 있는지 묻고 값을 얻는 것
        // 마우스(카메라)가 찍고 있는 방향을 월드좌표로 바꿔준다

        if (newAim.magnitude >= .9f)
        // Vector 값을 실수로 변환
        {
            CallLookEvent(newAim);
        }
    }

    public void OnFire(InputValue value)
    {
        Debug.Log("OnFire" + value.ToString());
    }
}
  • TopDownMovement 만들기
    • TopDownMovement는 실제로 움직임이 발생하는 부분임.
    • PlayerInputController는 지시만 하고 실제로 행동은 전혀 하지 않는 관리자
    • TopDownMovement는 실무를 하는 실무자
using UnityEngine;

// TopDownMovement는 캐릭터와 몬스터의 이동에 사용될 예정입니다.
public class TopDownMovement : MonoBehaviour
{
    // 실제로 이동이 일어날 컴포넌트
    private TopDownController movementController;
    private Rigidbody2D movementRigidbody;

    private Vector2 movementDirection = Vector2.zero;

    private void Awake()
    {
        // 주로 내 컴포넌트 안에서 끝나는 거를 많이 함

        // 같은 게임오브젝트의 TopDownController, Rigidbody를 가져올 것 
        movementController = GetComponent<TopDownController>();
        movementRigidbody = GetComponent<Rigidbody2D>();
    }

    private void Start()
    {
        // OnMoveEvent에 Move를 호출하라고 등록함
        movementController.OnMoveEvent += Move;
    }

    private void FixedUpdate()
    {
        // 물리 업데이트에서 움직임 적용
        // FixedUpdate는 물리업데이트 관련
        // rigidebody의 값을 바꾸니까 FixedUpdate
        ApplyMovement(movementDirection);
    }

    private void Move(Vector2 direction)
    {
        // 이동방향만 정해두고 실제로 움직이지는 않음.
        // 움직이는 것은 물리 업데이트에서 진행(rigidbody가 물리니까)
        movementDirection = direction;
    }

    private void ApplyMovement(Vector2 direction)
    {
        direction = direction * 5;

        movementRigidbody.velocity = direction;
    }
}
  • 플레이어 오브젝트 만들기

    • 빈 오브젝트 → Player 이름수정
    • Rigidbody 2D 추가 → Gravity Scale 0, Freeze Rotation Z
  • Player Hierarchy

    • 실제 플레이어 객체는 가만히 있고 보여지는 이미지(스프라이트)만 회전하는 경우도 있기 때문에 분리하여 계층 구조로 만들면 편리함
  • Player Inspector

    • Player Input 추가 → Actions - TopDown Controller 2D

      • 😺 Behavior 정리
        • Send Messages : 같은 게임오브젝트의 모든 컴포넌트에 뿌려지는 메시지를 날림
        • Broadcast Messages : 같은 게임오브젝트와 그 자식 게임오브젝트의 모든 컴포넌트에 뿌려지는 메시지를 날림 (굳이? 싶지만 편리할 때가 있긴 함)
        • Invoke Unity Event : OnClick처럼 UnityEvent형태로 관리됨. 편리함.
        • Invoke C Sharp Events : PlayerInput.OnActionTriggered 에 호출하고 싶은 이벤트 등록해서 어떤 이벤트인지 확인해서 쓸 수 있음
    • PlayerInputController , TopDownMovement 추가
    • Player에 이미지 드래그 하여 추가 → MainSprite 이름 변경

0개의 댓글