본문 바로가기
스파르타 내배캠

스파르타 내배캠 Unity 3기 22일차

by LemongO 2024. 1. 23.

쑥쑥 자라라 코딩실력아

 

 

 

 

이번주차 강의를 듣다보면 이런생각이 든다.

"오... 음음 그렇지. 이렇게 하면... 저렇게 되겠지? 그렇구나~"

 

이게... 이해 한 걸까?

이것은 마치 수학문제를 풀다가 배운 내용임에도 막상 응용문제를 풀려니 모르겠어서 답지를 보며 

"아~ 이거구나~" 하며 '이해한 척' 하는 급식시절 나의 모습과 유사하다.

 

그런 의미에서 TIL은 최강이다!


InputSystem 과 PlayerMove 로직

유니티의 InputSystem은 혼자 공부했을 땐 딱 한 번? 써본거같은 기억이 있다. 개인프로젝트 할 땐 써본적 없다.

이번 개인과제에서도 쓰질 않았는데 강의를 먼저 봤으면 쓰고 제출 했을텐데 그게 좀 아쉽다.

 

아무튼 InputSystem을 이용하면 각종 입력환경에서 대응이 쉽다는것은 알고있다.

 


InputSystem을 쓰기위해 패키지 매니저의 InputSystem 설치가 필요하다.

 

 

 

설치가 되었으면 프로젝트 창에서 Create - 가장밑의 Input Action을 생성한다.

생성된 InputAction을 켜주고 Control Scheme를 추가시켜준다.

 

Add Control Scheme

 

Scheme의 이름을 정해주고 리스트를 추가해준다.

키보드 마우스를 사용할 것이니 리스트에 Keyboard 와 Mouse를 추가시켜준다.

 

 

만들어진 Scheme가 선택되었으면

 

 

ActionMaps에 하나를 추가 시켜주고, Actions에 자동 생성된 Action에 설정을 변경시켜주자.

Action타입은 값을 받을 것이니 Value로 설정하고, 2D 게임이니 Vector2 타입으로 설정한다.

 

그리고 Action에 바인딩을 추가해주는데 2번째 Up Down Left Right Composite를 선택해주자.

 

2D Vector Composite가 생겼다

 

 

 

그 후 Up Down Left Right에 키보드 W S A D를 바인딩을 해주자

방향키로도 움직일 수 있으니 추가를 해주면 되지만, 일단 여기까지만 하도록 한다.

 

 

 

다음은 Player 오브젝트에게 PlayerInput 컴포넌트를 부착시키고 방금 만든 InputAction을 등록시켜준다.

Behavior 는 Send Messages 방식으로 해준다.

이 방식은 어떤 오브젝트의 모든 컴포넌트에 있는 함수를 이름으로 출력하는 방식이라고한다.

Action의 이름을 Move라고 지어줬기 때문에, 사용 가능한 함수는 OnMove라고 나와있다.

 

 

이제 InputSystem을 사용할 준비는 다 되었다. 나머지는 코드로 로직만 구현하면 된다.

강의 내용대로 따라가보자.

 

 


강의 내용대로 따라가보려고 잠시 강의를 다시 보고왔다.

아무래도 강의 내용을 요약해서 내 방식대로 해야할듯 하다.

 

하지만 사용한 코드나 스크립트는 동일하다.

 

 

이동에 쓰일 스크립트들은 세가지이다.

  • InputSystem을 이용하여 입력에 의한 Vector2 값을 받고 그 값을 전달할 PlayerInputController 스크립트
  • 실질적인 플레이어의 이동 로직을 담당하고, InputSystem에서 받은 Vector2 값으로 움직임을 실행하는 TopDownMovement 스크립트
  • Player의 모든 Input에 의해 실행될 함수들을 관리하고 위 둘을 중개해주는 TopDownCharacterController 스크립트

 

전체적인 흐름은 다음과 같았다.

  1. TopDownCharacterController 스크립트에서 구독할 함수를 받을 Action, 다른 클래스에서 해당 Action을 실행시킬 CallMoveEvent 함수를 작성한다.
  2. PlayerInputController 스크립트에서 InputSystem 을 이용한 입력을 감지 및 CallMoveEvent 를 호출.
  3. TopDownMovement 스크립트에서 Action에 구독할 함수인 Move 함수를 작성, 실제 이동로직 ApplyMovement 함수 를 작성 및 FixedUpdate 에서 호출.

 

public class TopDownCharacterController : MonoBehaviour
{
    public event Action<Vector2> OnMoveEvent;    

    public void CallMoveEvent(Vector2 direction)
    {
        OnMoveEvent?.Invoke(direction);
    }
}

OnMoveEvent  Action과 OnMoveEvent 를 외부에서 호출할 CallMoveEvent 함수

매개변수로 Vector2를 받는데 이동에 쓰일것이니 움직일 방향을 받게 된다.

그리고 OnMoveEvent 가 Invoke 될 때 해당 방향을 넘겨준다.

 

 

public class PlayerInputController : TopDownCharacterController
{
    protected override void Awake()
    {
        base.Awake();    
    }

    // WASD 또는 방향키 KeyDown & KeyUp 할 때 마다 호출 됨.
    // 본 강의에서 OnMove의 역할은 방향을 알려주는 역할로만 쓰임.
    // 실제 움직임을 담당하는건 TopDownMovement 클래스의 ApplyMovement 부분.
    public void OnMove(InputValue value)
    {        
        Vector2 moveInput = value.Get<Vector2>();
        CallMoveEvent(moveInput);
    }
}
public class TopDownMovement : MonoBehaviour
{
    private TopDownCharacterController _controller;    

    private Vector2 _movementDir;
    private Rigidbody2D _rigid;

    private void Awake()
    {
        _controller = GetComponent<TopDownCharacterController>();
        _rigid = GetComponent<Rigidbody2D>();
    }

    private void Start()
    {
        _controller.OnMoveEvent += Move;
    }

    private void FixedUpdate()
    {
        ApplyMovement(_movementDir);
    }

    private void Move(Vector2 direction)
    {
        _movementDir = direction;        
    }

    private void ApplyMovement(Vector2 direction)
    {
        direction = direction * 5f;
        _rigid.velocity = direction;
    }
}

PlayerInputController는 TopDownCharacterController를 상속받고있다.

하지만 아직까지는 상속을 받았다고해서 뭔가 상속을 이용한 뭔가를 하고있진 않다.

 

public void OnMove(InputValue value)

해당 함수로 InputAction 에 바인드 해둔 WASD 입력을 통해 Vector2 의 값을 value.Get<Vector2>()로 받을 수 있다.

 

그리고 실험해본 결과 OnMove의 함수는 Update 또는 FixedUpdate 방식이 아닌 바인드된 키가 Down 또는 Up 될 때 호출되는것을 확인했다.

 

Vector2 moveInput = value.Get<Vector2>();
CallMoveEvent(moveInput);

 

moveInput에 입력을 통한 Vector2 값을 저장 후, CallMoveEvent를 호출 해 주며 moveInput 값을 넘겨준다.

 

 

그리고 TopDownMovement 스크립트 내부를 잘 살펴보자. 솔직히 난 여기서 헷갈렸다.

 

private TopDownCharacterController _controller;

private Vector2 _movementDir;

private void Start()
{
    _controller.OnMoveEvent += Move;
}

private void Move(Vector2 direction)
{
    _movementDir = direction;        
}

많이 짤라내고 당장 집중해야할 코드들만 가져와봤다.

TopDownCharacterController 는 분명 '중개' 역할을 해주는 Action이 있다고 했다.

그 Action인 OnMoveEvent에 Move 함수를 구독시켜주자.

그리고 OnMoveEvent는 PlayerInputController에서 OnMove를 통해 호출하도록 했다.

 

다시보자..

public void OnMove(InputValue value)
{        
    Vector2 moveInput = value.Get<Vector2>();
    CallMoveEvent(moveInput);
}

CallMoveEvent(moveInput);
CallMoveEvent(moveInput);
CallMoveEvent(moveInput);

밑에 세 줄은 상기하려고 한거고 아무 의미없다.

 

그럼 CallMoveEvent는 어떤 처리를 해줄까?

public void CallMoveEvent(Vector2 direction)
{
    OnMoveEvent?.Invoke(direction);
}

그냥 OnMoveEvent를 호출하는 용도 이상 그 이하도 아니다.

 

자 그럼 구독된 함수는 뭐라고 작성되어 있는가?

private void Move(Vector2 direction)
{
    _movementDir = direction;        
}

Vector2 전역변수인 _movementDir 에 direction을 할당하도록 해준다.

좋다. 그럼 다시 여기까지 시간의 흐름에 따라 정리해보자. 

 

 

  1. InputSystem을 적용한 PlayerInputController 에서 OnMove 함수가 실행이 된다. (W S A D 입력)
  2. 입력에 의한 Vector2 값을 가지고 OnMoveEvent를 호출시킨다.
  3. 이 때, OnMoveEvent에는 Move함수가 구독되어 있고 해당 함수는 Vector2 전역변수 _movementDir 에 받아온 값을 할당한다.

여기까지 알 수 있는 사실은 InputSystem에 의한 실행결과값은 '방향' 을 알아냈고, 그 방향을 저장했다.

 

이제 실제 움직임을 구현하면 될 차례다.

 

private void FixedUpdate()
{
    ApplyMovement(_movementDir);
}

private void ApplyMovement(Vector2 direction)
{
    direction = direction * 5;
    _rigid.velocity = direction;
}

 

 

FixedUpdate 함수에서 ApplyMovement 함수를 호출한다. 이 때 방금 저장하는데 쓰인 전역변수를 넘겨준다.

ApplyMovement 함수는 방향 * 속도 값을 가지고 RigidBody2D.velocity 에 해당 방향*속도 값을 넣어줬다.

 

이렇게 해서 움직임을 구현했고 이를 아주 큰 단위로만 보면 다음과 같이 진행된다.

 

  • 입력을 했고 WASD 에 대응되는 방향 Vector2 를 값으로 받았다.
  • OnMoveEvent를 호출 시키고 이 때 방향 Vector2 를 넘겨준다.
  • 구독된 함수 내부에서 전역변수에 해당 방향을 저장한다.
  • 저장된 전역변수를 사용해 RigidBody2D에 속도를 준다.

 

 

이동에 쓰인 컴포넌트들

 

 

 

다 쓰고 나서 생각해보니 강의에선 해당 코드를 썼다.

public void OnMove(InputValue value)
{        
    Vector2 moveInput = value.Get<Vector2>().normalized;
    CallMoveEvent(moveInput);
}

 

normalized를 썻는데 나는 쓰지 않았다. 그 이유는 InputAction 에서 normalized 로 값을 받을 수 있기 때문이다.