Unity 개발일지

[Unity] New InputManager로 플레이어 이동 구현하기 본문

Unity 개발

[Unity] New InputManager로 플레이어 이동 구현하기

아머르 2024. 5. 8. 18:31

유니티로 플레이어의 이동을 구현하는 방법은 다양하다.

오늘은 그중에서도 New InputManager로 구현을 해보았다.

 

 

New InputManager란 무엇인가?

우선 기존의 InputManager (구 InputManager)로 플레이어의 이동을 구현해보았다.

[SerializeField] 는 private로 선언된 변수를 Inspector창에서 접근할 수 있게 해주는 함수이다.

Inspector 창의 InputManager 스크립트에서 접근자가 private속성인 speed를 설정할 수 있다.

 

기존 Update문에서 GetComponent를 사용하여 Rigidbody2D에 접근을 하였는데 매 프레임마다 가져올 필요가 없이

Start문에서 Rigidbody2D에서 접근하여 코드를 변경하였다. 매번  달라져야하는 경우에는 이 방법을 사용할 수 없다.

 

Input.GetAxisRaw는 유니티의 입력시스템에서 사용되는 메서드로 입력 축의 값을 반환한다.

GetAxis 메서드는 -1부터 1 사이의 값을 반환하는데 입력 장치의 움직임에 따라 해당 값이 변경된다.

GetAxisRaw("Vertical")과 GetAxisRaw("Horizontal")로 플레이어의 상하좌우 입력을 받아준 후

Vector2 direction으로 벡터화 시킨다.

 

direction.normalized는 벡터의 길이를 1로만드는 정규화 작업이다.

(1,0)의 경우는 벡터가 1이지만 (1,1)의 경우는 1.414(√2)의 값을 가지는데

이렇게 되면 대각선 이동 시 플레이어는 40%의 버프를 받게되는 셈이다!

 

 

그렇다면 InputManager, 무엇이 문제인가?

1. 조이스틱 등 다양한 입력장비 대응 부족
  InputManager에서는 다양한 플랫폼에 대응하거나 키를 변경하는 리바인딩이 부족하다.

  (요즘 키를 커스텀할 수 있는 기능은 기본중의 기본이다.)

 

2. 입력 처리와 실제 로직 실행 주체를 분리
  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-Playform Compatibility

  New Input System은 다양한 플랫폼과 입력 장치에 대해 일관된 방식으로 작동합니다.


2. Rebinding

  플레이어가 게임 내에서 자신의 입력 설정을 변경할 수 있도록 지원합니다.


3. Multiplayer Support

  여러 플레이어가 동일한 장치에서 게임을 플레이하거나, 각각의 장치에서 게임을 할 때 입력을 쉽게 처리할 수 있습니다.

 

 

그렇다면 NewInputManager로 플레이어의 이동을 다시 구현해보자!

게임의 용량 관리를 위해 NewInputManager(이하 InputManger)는 Package Manager에서 Instrall해줘야한다.

Window - Package Manager - 기존의 In Project를 Unity Registry로 변경 - InputManager 검색 - Install

유니티가 재시작 된 후 Package Manager에 들어갔을 때 Remove 버튼으로 바뀌어있다면 성공적으로 다운 받아진 것!

 

이제 Project 창에 Input 폴더를 만들고 우클릭해서 보면 Input Action이라는 새로운 것을 만들 수 있다.

 

 

이름을 TopDownController2D로 만들고 더블클릭을 해보자.

 

 

창이 하나 뜨는데 KeyboardMouse로 Control Scheme을 하나 만들어주자.

 

 

Scheme Name을 바꾼 뒤  List is Empty 밑에 +버튼을 눌러 키보드와 마우스를 더해준다.

(22.3.17 버전 기준으로 우클릭으로 클릭해야합니다)

 

 

Action Maps 옆의 + 버튼과 Actions 옆의 + 버튼을 눌러 위의 그림처럼 생성시켜줍니다.

 

 

1. Action의 Action Type을 Value(값), Control Type을 Vector 2로 설정한다.

2. Move 옆의 + 를 클릭하여  Add Up Down Left Right Composite를 더해준다.

3. Up, Down, Left, Right를 눌러 Path에 각각의 값을 키보드로 입력해준다.

   (Up의 Path를 누르고 W키를 누르면 W키를 눌러 지정할 수 있다)

4. Save Asset을 눌러 저장한다.

(이번 포스팅에서는 Move만 구현할 것이므로  Look과 Fire는 만들지 않아도 상관없다.)

 

1. Hierachy 창에서 빈 오브젝트 생성 - Player로 이름 변경

2. Player에 Rigidbody 2D 추가 - Gravity Scale 0, Freeze Ratation Z 체크

3. Player에 Player Input 추가 - Actions - TopDown Controller 2D로 설정

4. Player Input의 Actions에 TopDownController2D 드래그드롭 or 적용

5. Player Input의 Behavior - Send Messages로 설정

Player 게임오브젝트의 모든 컴포넌트에 OnMove, OnLook, OnFire 메세지를 날려 실행시킨다.

그러므로 OnMove, OnLook, OnFire과 같은 이름의 함수를 만들면 된다! (대소문자주의!!!!)

앞에 붙은 On은 앞서 만든 Move, Look, Fire 앞에 붙는 Send Messages의 디폴트 값이다.

 

6. Player의 자식으로 빈 오브젝트 MainSprite 생성, Sprite Render 컴포넌트 추가, 원하는 이미지 넣기

이제 InputManager의 기본적인 설정은 끝났고, 스크립트를 만들어서 마저 구현해주면 된다.

 

 

 

<Player 이동만 샘플을 만들면서 구현한 내용입니다>

 

샘플로 만든 프로젝트에서는 이동 관련은 MainPlayer만 할것이기 때문에 하나의 스크립트에 작성했다.

PlayerInputController 스크립트를 만들어주었고, Action으로 OnmoveEvent를 선언했고,

강체의 움직임과 관련된 Rigidbody2D와 방향을 받아줄 Vector2를 선언해주었다.

 

Awake에서 Rigidbody2D를 받아왔고, Start에서 OnMoveEvent가 발생하면 움직이도록(Move) 해줬다.

 

이제 New InputManager의 꽃인 OnMove 함수를 작성해주자. (대소문자 주의!!!)

OnMove 함수는 앞서 설정했던 키입력을 받으며 받은 키입력을 moveInput에 저장해 normalized(단위벡터)화 한 후에

움직임을 발생(Invoke)시킨다.

 

FixedUpdate에서 ApplyMovement 함수가 작동하는데 플레이어의 속도를 정해준다.

 

PlayerInputController.cs를 Player의 컴포넌트로 넣어주면 끝!

 

이렇게만 작성해줘도 플레이어의 움직임은 구현된다.

 

 

<아래 부분은 강의 내용을 따라가며 작성한 내용입니다>

 

[스크립트 설계]

컨트롤러는 어떤 오브젝트의 상황에 따라 행동을 결정하고,

TopDownMovement와 같이 실제 로직을 수행하는 컴포넌트들에 이벤트를 전달하는 역할을 한다.

하지만 컨트롤러는 플레이어 뿐 아니라 에게도 적용될 수 있으므로 일단 PlayerInputController를 만들어주고,

적에게도 사용되는 공통적 기능들은 TopDownController에 정의하여 이를 재활용한다.

 

 

[TopDownController.cs]

이동과 관련된 액션들을 모두 실행하는 CallMoveEvent,

마우스와 관련된 이벤트를 모두 실행하는 OnLookEvent를 정의하고 호출하는 기능 작성해주었다.

 

TopDownController 에서는 Action들을 만들어주고 event를 통해 이를 통제하고,

TopDownMovement에서 MoveEvent 발생 시 해당 함수를 Invoke 해준다.

CallLookEvent는 지금은 쓰이지 않는다.

 

 

[PlayerInputContoller.cs]

PlayerInputController는 TopDownController를 상속받는다.

해당 cs에서는 움직이라고 지시만 하고 실제 움직임은 TopDownMovement에서 한다.

 

OnLookEvent는 지금은 쓰이지 않지만 간단하게 설명하면

worldPos에서 카메라를 기준으로 마우스가 있는 곳의 스크린좌표를 월드좌표로 바꾸어준다.

그리고 newAim값을 바꿔주는데, 캐릭터에서 마우스로의 벡터를 구하기 위해

(마우스좌표 - 플레이어좌표)를 한 후 normalized로 단위벡터화 해주었다.

 

참고로 OnLook 부분의 함수를 보면 look으로 작성되어있어서 오류가 났었다...ㅎ (대소문자주의...!)

 

[TopDownMovement.cs]

실질적인 움직임은 TopDownMovement.cs에서 일어나기 때문에 controller와 movementRigidbody를 필드로 선언했고,

Awake함수로 게임 시작 시 접근할 수 있도록 했다.

 

ApplayMovement 함수는 rigidbody의 값을 바꾸는 물리업데이트 관련이기 때문에 FixedUpdate에 선언해주었고,

Move함수는 Update기반(프레임단위)으로  Move함수의 movementDirection에 걸어놓고,

실제 처리는 FixedUpdate의 ApplyMovement에서 적용 해주었다.

 

 

PlayerInputController.cs 와 TopDownMovement.cs 를 Player의 컴포넌트로 넣어주면 끝!

작동이 잘 되는 모습이다.

반응형