
이번 주차에 들어서며, 본격적인 Unity에 대한 주차가 시작되었다.
유니티 내에서 사용자가 입력하여 특정 스프라이트를 조작할 수 있게 하는 방법은 많지만,
이번에 사용해볼 것은 Input System을 통해 캐릭터 조작을 구현해 볼 것이다.

Package Manager에서 Input System 패키지를 설치해야 이용할 수 있다.
이 Input System을 이용할 시에는 다양한 이점을 얻을 수 있다.
우선, Input System에선 기본적인 키보드나 마우스 뿐 만 아니라, 터치나 게임패드같은 입력또한 다룰 수 있다.
그리고 사용자가 조작키를 바꾸는 기능을 구현하게 할 수 있다.
만약 1P, 2P가 한 키보드에서 조작을 해야하는 상황에서도, 입력을 쉽게 처리할 수 있다.
해당 패키지를 설치하고 나서는, Input Actions라는 것을 생성할 수 있다.

상단의 이미지는 이미 생성된 Input Action이다.
위의 All Control Scheme을 누르고 새로운 Control Scheme을 생성할 수 있다.

Control Scheme는 입력장치를 어떤 것을 받을 지 선택하는 것이다.
우선, 키보드를 통해 움직이고, 캐릭터가 마우스 방향을 바라보게 하는 식의 조작을 구현할 것이다.
Keyboard와 Mouse를 추가하고 한다.

현재 구현하고자 하는 입력은 플레이어의 입력이므로, Action Maps에 Player를 추가했다.
그리고 Actions에는 움직임을 입력할 Move와 바라보는 방향인 Look를 추가했다.

Move는 키보드 wasd를 눌렀을 때, 상하좌우를 움직이게 하는 움직임을 입력받을 것이다.
Action Type을 Value로 맞추고 Control Type을 Vector2로 맞춘다.

Move 옆에 있는 '+' 기호를 누르면, Binding에 대한 몇몇 프리셋이 준비되어 있다.
상하 좌우 움직임을 구현하고자 하므로, Add Up... 으로 시작하는 버튼을 누르면,
사진과 같이 Up, Down, Lef, Right 입력이 추가된다.

상단 이미지는 위로 움직이는 것에 대한 Binding 이다 Path를 통해 키를 지정할 수 있다.

Look의 경우는 마우스 위치에 따라 조작할 예정이니, Path에 Mouse Position을 설정한다.
이를 완료하면 사용자의 입력을 받을 준비는 끝난다.
이제 이 입력을 통해 캐릭터를 움직이게 할 일만 남았다.
우선 다음과 같은 식으로 입력과 작동을 구현할 것이다.
우선 플레이어와 NPC를 포함한 모든 캐릭터를 움직이게 할 수 있는 스크립트인 CharaController를 다음과 같이 만들 것이다.
using System;
using UnityEngine;
public class CharaController : MonoBehaviour
{
public event Action<Vector2> OnMoveEvent;
public event Action<Vector2> OnLookEvent;
public void CallMoveEvent(Vector2 direction)
{
OnMoveEvent?.Invoke(direction);
}
public void CallLookEvent(Vector2 direction)
{
OnLookEvent?.Invoke(direction);
}
}
MoveEvent는 이동과 관련된 값을 받을 수 있을 것이고,
LookEvent는 마우스의 위치를 입력받을 수 있을 것이다.
그리고 이 CharaController를 상속받는 PlayerInputController를 작성한다.
using UnityEngine;
using UnityEngine.InputSystem;
public class PlayerInputController : CharaController
{
private Camera _camera;
private void Awake()
{
_camera = Camera.main;
}
public void OnMove(InputValue value)
{
Vector2 moveInput = value.Get<Vector2>().normalized;
CallMoveEvent(moveInput);
}
public void OnLook(InputValue value)
{
Vector2 newAim = value.Get<Vector2>();
Vector2 worldPos = _camera.ScreenToWorldPoint(newAim);
newAim = (worldPos - (Vector2)transform.position).normalized;
CallLookEvent(newAim);
}
}
본 스크립트는 플레이어의 입력에 관련된 내용을 관리한다.
OnMove에서는 이동키를 눌러 입력된 벡터 값을 CallMoveEvent로 보내게 되고,
OnLook에서는 마우스의 위치를 CallLookEvent로 보내게 된다.
이 스크립트는 입력을 받기만 하지, 실제로 움직이는 기능을 하지는 않는다.
이제 움직이기 위한 스크립트를 다음과 같이 작성할 수 있다.
using UnityEngine;
public class CharaMovement : MonoBehaviour
{
private CharaController movementController;
private Rigidbody2D movementRigidbody;
private Vector2 movementDirection = Vector2.zero;
private void Awake()
{
movementController = GetComponent<CharaController>();
movementRigidbody = GetComponent<Rigidbody2D>();
}
private void Start()
{
movementController.OnMoveEvent += Move;
}
private void FixedUpdate()
{
// 움직임함수 작동
ApplyMovement(movementDirection);
}
private void Move(Vector2 direction)
{
// 방향 설정
movementDirection = direction;
}
private void ApplyMovement(Vector2 direction)
{
// 움직임 함수
direction = direction * 5;
movementRigidbody.velocity = direction;
}
}
우선 입력된 값을 받아오기 위해 Controller와,
스프라이트를 움직이기 위해 Rigidbody 2D 컴포넌트를 받아올 수 있게 해야한다.
움직이는 방향을 받을 movementDirection은 Vector2.zero로 초기화한다.
Start에서 OnMoveEvent에 Move메서드를 입력한다.
Move메서드는 입력에 따라 방향을 지정하는 메서드이다.
ApplyMovement 메서드는 Rigidbody를 조작해 실제 움직임을 구현하는 메서드이다.
물리와 관련된 메서드이므로 FixedUpdate를 통해 작동시킨다.
캐릭터에 Rigidbody2D 컴포넌트와 Player Input 컴포넌트, 그리고 지금까지 작성한 스크립트 컴포넌트를 추가한다.

CharaController는 어처피 PlayerInputController가 상속받아 사용하므로, 추가할 필요 없다.
Player Input에 Actions를 아까 생성했던 Input Actions를 넣고 게임을 실행시켜보면 입력받은대로 캐릭터가 움직일 수 있다.
다음에는 캐릭터를 회전시킬 때는 아크탄젠트를 이용하여 마우스포인트의 위치를 통해 각도를 알아내고,
그 각도값에 따라 스프라이트를 반전시키는 방식으로 구현하고자 한다.
다음과 같은 CharaRotation 스크립트를 추가한다,
using UnityEngine;
public class CharaRotation : MonoBehaviour
{
[SerializeField] private SpriteRenderer characterRenderer;
private CharaController rotationController;
private void Awake()
{
rotationController = GetComponent<CharaController>();
}
void Start()
{
rotationController.OnLookEvent += OnAim;
}
public void OnAim(Vector2 newAimDirection)
{
Rotate(newAimDirection);
}
private void Rotate(Vector2 direction)
{
float rotZ = Mathf.Atan2(direction.y, direction.x) * Mathf.Rad2Deg;
characterRenderer.flipX = Mathf.Abs(rotZ) > 90f;
}
}
마우스 위치에 따라 뒤집을 것이므로, 캐릭터의 SpriteRenderer 컴포넌트를 받아와야한다.
이동때와 마찬가지로, 컨트롤러도 받는다.
OnAim을 OnLookEvent에 추가하고,
OnAim 메서드는 캐릭터를 회전시키는 Rotate메서드를 작동시킨다.
Rotate메서드에 있는 Atan2는 아크탄젠트 메서드로, 어떤 직각 삼각형의 세로가 y, 가로가 x일 때, 그 각도를 라디안[-pi,pi] 로 나타내는 메서드이다. 그 값에 Mathf.RadDeg를 곱해, 라디안 값을 Degree값으로 바꿔준다.
characterRenderer.flipX = Mathf.Abs(rotZ) > 90f; 는 이 rotZ의 값이 -90~90일 때는 캐릭터 스프라이트의 flipX를 false로 하지만,
-90보다 작고, 90보다 커진다면 flipX를 true로 해 스프라이트가 반전되는 기능을 한다.
'내일배움캠프 TIL' 카테고리의 다른 글
| 내일배움캠프 19일차 TIL "맵 내 존재하는 캐릭터들 이름 출력" (0) | 2024.10.10 |
|---|---|
| 내일배움캠프 18일차 TIL "Scriptable Object를 이용한 캐릭터 정보 적용" (0) | 2024.10.08 |
| 내일배움캠프 16일차 TIL "ref, out" (0) | 2024.10.04 |
| 내일배움캠프 15일차 TIL "상태 머신" (0) | 2024.10.02 |
| 내일배움캠프 14일차 TIL "텍스트게임 장비 구현2" (0) | 2024.10.01 |