이 글은 다음의 내용을 참고하여 작성하였습니다.
해당 프로젝트에서는 주인공 프리팹과 2개의 애니메이션(idle, walk)이 제공된다.
왼쪽/오른쪽으로 꺾는 애니메이션이 없기 때문에 해당 애니메이션은 주인공 오브젝트 자체를 이동 방향으로 회전하는 방식으로 구현한다.
void FixedUpdate() {
Vector3 movement;
Quaternion rotation;
float horizontal = Input.GetAxis("Horizontal");
float vertical = Input.GetAxis("Vertical");
movement.Set(horizontal, 0f, vertical);
movement.Normalize();
float turnSpeed = 20f;
Vector3 desiredForward = Vector3.RotateTowards(transform.forward, movement, turnSpeed * Time.deltaTime, 0f);
rotation = Quaternion.LookRotation(desiredForward);
...
}
Input.GetAxis("Horizontal");
//왼쪽 이동 키(←, a키)가 입력되면 0 ~ -1 값을, 오른쪽 이동키 (→, d키)가 입력되면 0 ~ 1 값을 리턴
Input.GetAxis("Vertical");
//아래쪽 이동 키(↓, s키)가 입력되면 0 ~ -1 값을, 오른쪽 이동키 (↑, w키)가 입력되면 0 ~ 1 값을 리턴
유니티 Edit > Project Settings > InputManager > Axes에서 GetAxis() 에 들어가는 인수 "Horizontal"과 "Vertical"의 정보를 확인할 수 있다.
Input.GetAxis()의 리턴값은 움직이지 않을 수록 0에, 해당 방향으로 움직일 수록 1 또는 -1에 가까워진다.
movement.Set(horizontal, 0f, vertical);
//플레이어가 움직일 방향을 나타내는 벡터 movement를 설정한다.
movement.Normalize();
//벡터의 방향은 그대로, 크기는 1로 만들어준다.
Normalize 과정을 거치지 않으면 플레이어는 대각선으로 이동할 때 더 빠르게 이동하며, 이는 의도하지 않은 동작이므로 Normalize 과정이 필요하다.
Vector3.RotateTowards(Vector3 current, Vector3 target, float maxRadiansDelta, float maxMagnitudeDelta);
//current 벡터를 target 벡터를 항하도록 회전한 값을 리턴하는 것 같다. (원문: Rotates a vector current towards target.)
//maxRadiansDelta는 각도의 변화량, maxMagnitudeDelta는 크기의 변화량을 의미한다.
transform.forward
//해당 transform을 가진 오브젝트에서 정면(Z축)을 보는 크기 1의 벡터를 리턴한다.
명확하게 이해되지는 않지만 Vector3.RotateTowards()는 current 벡터와 target 벡터를 참고하여 회전 벡터를 리턴하는 것 같다.
maxRadiansDelta의 경우 값이 올라가면 회전 속도가 빨라지고, 내려가면 느려진다.
Quaternion.LookRotation(Vector3 forwards)
//벡터 forwards 방향을 바라보는 회전 상태(Quaternion)를 반환한다.
오브젝트의 회전값을 가지는 transform.rotation은 쿼터니언으로만 수치를 조정할 수 있다.
따라서 Vector3.RotateTowards()로 얻은 desiredForward(원하는 회전 방향) 벡터 값을 오브젝트에 적용하기 위해서 Quaternion.LookRotation()을 통해 쿼터니언으로 변환한다.
쿼터니언은 유니티에서 내부적으로 각도를 다루는 방법이며, 자세한 내용은 나중에 제대로 공부해 보아야 할 것 같다.
void FixedUpdate() {
...
rigidbody.MovePosition(rigidbody.position + movement);
rigidbody.MoveRotation(rotation);
}
이전에 계산해놓은 movement 벡터와 rotation 쿼터니언 변수를 사용한다.
계산한 값을 오브젝트의 rigidbody에 적용한다.
bool hasHorizontalInput = !Mathf.Approximately(horizontal, 0f);
bool hasVerticalInput = !Mathf.Approximately(vertical, 0f);
bool isWalking = hasHorizontalInput || hasVerticalInput;
Mathf.Approximately(float a, float b);
//a가 b와 근사하면 true, 아니면 false를 리턴한다.
horizontal이 0 에 근사하면
Mathf.Approximately(horizontal, 0f) 는 true,
!Mathf.Approximately(horizontal, 0f) 는 false가 되며
수평 움직임이 있는지 체크하는 hasHorizontalInput 이 올바른 값(false)을 가지게 된다.
변수 isWalking은 애니메이션 설정 관련에서 유용하게 사용할 수 있다.
이동 방향에 맞게 움직이고 오브젝트가 회전하는 것을 확인할 수 있다. ‡