개요
유니티에서 WASD 입력을 이용해 캐릭터를 이동하는 법을 알아보자.
캐릭터는 유니티의 기본 3D 오브젝트 Cube 2개를 사용해 임시로 만들었다. 파란 큐브가 정면이다.
이번 포스팅에선 두 가지 방법으로 위 캐릭터를 이동해 볼 예정이다.
- Input.GetKey를 활용해 움직임을 구현
- Input.GetAxis를 활용해 움직임을 구현
공통 코드 및 환경
두 가지 방법에서 공통적으로 사용하는 환경과 코드이다.
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class CubeScript : MonoBehaviour
{
// 속도를 인스펙터 상에서 설정
public float moveSpeed;
public float rotSpeed;
// 벡터값 초기화
private Vector3 moveDirection = Vector3.zero;
private Vector3 rotDirection = Vector3.zero;
public GameObject myCharacter;
private Rigidbody _rigidbody;
private void Awake()
{
// Rigidbody 컴포넌트 불러오기
_rigidbody = GetComponent<Rigidbody>();
}
private void Update()
{
// 키보드 입력 받기
}
private void FixedUpdate()
{
// 움직임 적용
}
}
공통 코드
공통으로 사용하는 코드이다.
Update에서는 키보드 입력을 받을 것이고, FixedUpdate에서는 Update에서 입력받은 값을 적용시킬 것이다.
입력과 적용을 각각 Update와 FixedUpdate에서 하는 이유는 다음과 같다.
Update 함수는 매 프레임마다 한 번씩 실행된다. FixedUpdate 함수는 매 프레임마다가 아닌 정해진 시간마다 한 번씩 실행된다. FixedUpdate의 디폴트 시간은 0.2초이다.
이때 만약 Update 함수에서 입력을 받아 바로 적용 시키는 코드를 작성하게 되면, 받은 입력에 대한 값을 적용시키기 전에 다음 Update 함수가 호출되어 버려서 입력이 씹혀버리게 될 수가 있다.
위 문제를 해결하기 위해 입력은 항상 자주 실행되는 Update에서 받고, 값 적용은 Update에서 입력받은 뒤 FixedUpdate에서 적용하게 하여 입력이 씹히는 일을 방지한다.
공통으로 사용하는 유니티의 씬과 인스펙터이다.
Cube의 MoveSpeed는 5, RotSpeed는 180으로 설정하였다. 이때 MoveSpeed는 앞, 뒤로 이동할 때의 속도이고 RotSpeed는 좌, 우 회전하는 각을 나타낸다. 기본적인 Cube 오브젝트에 Rigidbody 컴포넌트만 추가했다.
Rigidbody 컴포넌트의 Freeze Rotation x, y, z를 체크하면 캐릭터가 넘어지는 것을 방지하기에 체크하였다.
메인 카메라를 탑뷰 형식으로 캐릭터를 위에서 바라보게 하였다.
Input.GetKey를 활용해 움직임을 구현
private void Update()
{
moveDirection = Vector3.zero;
rotDirection = Vector3.zero;
if (Input.GetKey(KeyCode.W))
{
moveDirection = myCharacter.transform.forward;
}
if (Input.GetKey(KeyCode.A))
{
rotDirection = -myCharacter.transform.right;
}
if (Input.GetKey(KeyCode.S))
{
moveDirection = -myCharacter.transform.forward;
}
if (Input.GetKey(KeyCode.D))
{
rotDirection = myCharacter.transform.right;
}
// 벡터 정규화
moveDirection.Normalize();
rotDirection.Normalize();
}
private void FixedUpdate()
{
// 앞뒤 움직임
if (moveDirection != Vector3.zero)
{
Vector3 nextPostion = Vector3.MoveTowards(transform.position,
transform.position + moveDirection * 1000.0f, Time.fixedDeltaTime * moveSpeed);
_rigidbody.MovePosition(nextPostion);
}
// 좌우 회전
if (rotDirection != Vector3.zero)
{
Quaternion newRot = Quaternion.RotateTowards(myCharacter.transform.rotation,
Quaternion.LookRotation(rotDirection), Time.fixedDeltaTime * rotSpeed);
_rigidbody.MoveRotation(newRot);
}
}
Input.getKey(KeyCode.입력) 함수를 사용해 키보드 입력을 받는다.
- W - 캐릭터 기준 정면의 방향 벡터 값을 moveDirection에 저장한다.
- A - 캐릭터 기준 왼쪽 방향 벡터 값을 rotDirction에 저장한다. ( transform.right에 음수 부호를 붙여 사용 )
- S - 캐릭터 기준 뒷쪽 방향 벡터 값을 moveDirection에 저장한다.
- D - 캐릭터 기준 오른쪽 방향 벡터 값을 rotDirction에 저장한다. ( transform.forward에 음수 부호를 붙여 사용 )
Input.GetAxis를 활용해 움직임을 구현
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class CubeScript : MonoBehaviour
{
// 인스펙터 상에서 설정
public float moveSpeed;
public float rotSpeed; // rotSpeed값은 2로 수정
private Vector3 moveDirection = Vector3.zero;
private Vector3 rotDirection = Vector3.zero;
private Rigidbody _rigidbody;
private float horizontal = 0.0f;
private float vertical = 0.0f;
private void Awake()
{
// Rigidbody 컴포넌트 불러오기
_rigidbody = GetComponent<Rigidbody>();
}
private void Update()
{
moveDirection = Vector3.zero;
rotDirection = Vector3.zero;
// A, D를 누르면 Horizontal 값이 변하고 저장된다.
horizontal = Input.GetAxis("Horizontal");
rotDirection = transform.right * horizontal;
// W, S를 누르면 Vertical 값이 변하고 저장된다.
vertical = Input.GetAxis("Vertical");
moveDirection = transform.forward * vertical;
// 벡터 정규화
moveDirection.Normalize();
rotDirection.Normalize();
}
private void FixedUpdate()
{
// 앞뒤 움직임
if (moveDirection != Vector3.zero)
{
Vector3 nextPosition = Vector3.MoveTowards(transform.position,
transform.position + moveDirection * 1000.0f, Time.fixedDeltaTime * moveSpeed);
// fixedDeltaTime == 0.02초 프로젝트 설정
// 50번 불리니까
// fixedDeltaTime * MoveSpeed = 1tick당 이동할 거리
// 거리
// ---------------
// 속력 | 시간
_rigidbody.MovePosition(nextPosition);
}
// 좌우 회전
if (rotDirection != Vector3.zero)
{
// 쿼터니언을 Degree로 구하기
Vector3 nextRotation = Vector3.RotateTowards(transform.forward,
rotDirection, Time.fixedDeltaTime * rotSpeed, 0.0f);
_rigidbody.MoveRotation(Quaternion.LookRotation(nextRotation));
}
}
}
Input.GetAxis 함수를 사용해 W, A, S, D의 입력을 받아 사용한다.
- W, S - Vertical 값이 입력에 따라 -1 ~ 1 의 값을 가진다. W는 양수, S는 음수이다.
- A, D - Horizontal 값이 입력에 따라 -1 ~ 1 의 값을 가진다. D는 양수, A는 음수이다.
Input.GetAxis로 값을 받을 경우 Vertical과 Horizontal의 값은 -1에서 1사이의 값을 가진다.
예를 들어 초기값은 0이고 W를 꾸욱 누르면 1까지 증가하고 짧게 누르면 0.1 등의 1보다 작은 값이 저장된다.
이를 이용해 특정값을 넘어서면 캐릭터가 달리는 모션을 행하도록 하는 등 애니메이션과 같이 사용하기 편리하다.
구현 결과
'공부 > Unity' 카테고리의 다른 글
[Unity] 유니티로 태양계 만들기 (2) | 2024.07.11 |
---|