Unity - '한 우산 아래'

Unity에서 이동 방향을 바라보는 플레이어 회전 만들기

망고와플 2026. 4. 12. 00:10

Rigidbody 기반 이동과 회전 조작감 다듬기

쿼터뷰 게임에서 플레이어 이동을 만들 때 처음에는 단순히 입력 방향으로 위치나 속도를 바꾸는 방식으로 시작하기 쉽다. 나도 처음에는 WASD 입력을 받아서 캐릭터를 움직이고, 카메라 기준으로 앞뒤좌우를 계산하는 정도에서 출발했다.

하지만 실제로 조작해보면 단순한 이동만으로는 부족했다. 캐릭터가 어느 방향을 보고 있는지, 방향을 바꿀 때 몸이 얼마나 자연스럽게 따라오는지, 뒤로 방향을 바꿀 때 발이 미끄러지는 느낌이 있는지가 조작감에 꽤 크게 영향을 줬다.

그래서 이번에는 PlayerMovement.cs를 기준으로 플레이어 이동과 회전 방식을 조금 더 자연스럽게 다듬었다.

기존 이동 방식의 한계

처음 이동은 입력 방향에 맞춰 Rigidbody의 수평 속도를 직접 바꾸는 방식에 가까웠다. 이 방식은 반응이 빠르고 구현도 단순하지만, 캐릭터가 즉시 목표 속도로 움직이기 때문에 다소 딱딱하게 느껴졌다.

특히 이런 문제가 있었다.

문제 설명
출발과 정지가 즉각적임 가속/감속 과정이 없어 움직임이 기계적으로 느껴짐
방향 전환이 급격함 앞에서 뒤로 바꿀 때 캐릭터가 미끄러지는 느낌이 남
회전과 이동이 따로 노는 느낌 캐릭터가 아직 돌지 않았는데 몸은 이미 다른 방향으로 이동함
애니메이션 연결이 어려움 나중에 걷기/회전 애니메이션을 붙일 때 발 밀림이 생길 수 있음

이 문제를 줄이기 위해 이동을 속도 직접 대입이 아니라 가속/감속 기반으로 바꾸기 시작했다.

Rigidbody 기반 가속 이동으로 변경

현재 이동은 AddForce를 사용한다. 다만 일반적인 힘 누적 방식으로 마구 밀어내는 것이 아니라, 목표 속도와 현재 속도의 차이를 계산한 뒤 그 차이를 가속도 범위 안에서 보정하는 방식이다.

핵심 흐름은 다음과 같다.

  1. 카메라 기준 forward, right를 구한다.
  2. 입력값을 카메라 기준 이동 방향으로 변환한다.
  3. 목표 속도와 현재 수평 속도의 차이를 계산한다.
  4. 필요한 가속도를 구한다.
  5. 지상/공중 상태에 따라 가속도를 제한한다.
  6. Rigidbody.AddForce(..., ForceMode.Acceleration)로 적용한다.

현재 관련 변수는 다음과 같다.

변수  역할
moveSpeed 목표 최대 이동 속도
groundAcceleration 지상에서 목표 속도까지 붙는 가속도
groundDeceleration 지상에서 입력을 놓았을 때 줄어드는 감속도
airAcceleration 공중에서의 가속도
airDeceleration 공중에서 입력을 놓았을 때의 감속도

이렇게 바꾸면 입력을 누르는 순간 바로 최대 속도가 되는 것이 아니라, 일정한 가속을 거쳐 목표 속도에 도달한다. 덕분에 움직임이 조금 더 물리적으로 느껴진다.

이동 방향을 바라보도록 회전시키기

이동이 자연스러워지면 다음으로 필요한 것은 회전이다. 캐릭터가 이동 방향을 바라보지 않으면, 쿼터뷰에서도 조작이 어색하게 느껴진다.

현재 코드는 이동 방향이 있을 때 Quaternion.LookRotation으로 목표 회전을 만들고, Rigidbody.MoveRotation으로 회전한다.

Quaternion targetRotation = Quaternion.LookRotation(moveDirection, Vector3.up);
Quaternion nextRotation = Quaternion.RotateTowards(
    rb.rotation,
    targetRotation,
    effectiveTurnSpeed * Time.fixedDeltaTime
);

rb.MoveRotation(nextRotation);

여기서 중요한 점은 transform.rotation을 직접 바꾸지 않고 Rigidbody.MoveRotation을 사용한다는 것이다. 플레이어가 Rigidbody 기반으로 움직이고 있기 때문에, 회전도 물리 업데이트 흐름에 맞춰 처리하는 편이 더 안정적이다.

변수 역할
turnSpeed 이동 방향을 바라보는 기본 회전 속도
facingOverrideTurnSpeedMultiplier 우산 붓기처럼 조준이 필요한 상태에서 회전을 더 빠르게 하는 배율

뒤로 꺾을 때 발이 밀리는 문제

캐릭터가 앞으로 달리다가 갑자기 뒤로 입력을 넣으면, 애니메이션 관점에서는 바로 뒤로 미끄러지는 것처럼 보일 수 있다. 나중에 걷기/회전 애니메이션을 붙이면 이 문제가 더 크게 느껴질 가능성이 있다.

그래서 방향 차이가 클수록 이동 속도를 줄이는 보정을 넣었다.

현재 흐름은 이렇다.

  1. 캐릭터가 바라보는 방향을 구한다.
  2. 입력 이동 방향과의 각도를 계산한다.
  3. 각도가 작으면 그대로 이동한다.
  4. 각도가 커질수록 이동량을 줄인다.
  5. 거의 반대 방향이면 잠깐 회전에 더 집중한다.

관련 변수는 다음과 같다.

변수 역할
turnSlowdownStartAngle 이 각도부터 회전 중 감속을 시작
turnLockAngle 이 각도 이상이면 이동을 거의 멈추고 회전에 집중

이 방식은 완전히 돌기 전까지 절대 못 움직인다처럼 딱딱하게 막는 것이 아니라, 방향 차이에 따라 이동량을 부드럽게 줄이는 방식이다.

(사실 처음에는 완전히 돌고 움직이게 했는데 그러니까 개인적으로 너무 답답했다.)

그래서 발 밀림은 줄이면서도 조작이 너무 답답해지지 않도록 했다.

float t = Mathf.InverseLerp(turnLockAngle, turnSlowdownStartAngle, angleToMoveDirection);
return Mathf.SmoothStep(0.0f, 1.0f, t);

이 부분은 애니메이션을 위한 사전 작업에 가깝다. 지금은 임시 캡슐 캐릭터지만, 나중에 실제 캐릭터 애니메이션이 들어갔을 때 발이 미끄러지는 느낌을 줄이는 데 도움이 될 수 있다.

우산 사용 중에는 바라보는 방향을 override하기

플레이어는 기본적으로 이동 방향을 바라본다. 하지만 우산으로 물을 붓는 상황에서는 조금 다르다. 이동 방향보다 “어디를 향해 물을 붓는가”가 더 중요하다.

그래서 PlayerMovement에는 외부 시스템이 잠시 바라보는 방향을 지정할 수 있는 구조를 추가했다.

public void SetFacingOverride(Vector3 worldDirection)
{
    worldDirection.y = 0.0f;

    if (worldDirection.sqrMagnitude < MoveInputThreshold)
    {
        return;
    }

    hasFacingOverride = true;
    facingOverrideDirection = worldDirection.normalized;
}

우산 시스템은 물을 붓는 동안 마우스로 피킹한 방향을 계산하고, 그 방향을 플레이어 회전 override로 넘긴다. 그러면 플레이어는 이동 방향이 아니라 물을 붓는 방향을 바라보게 된다.

이 구조는 단순히 우산 하나만을 위한 것이 아니라, 나중에 다른 상호작용에서도 쓸 수 있다. 예를 들어 특정 오브젝트를 조사하거나, 버튼을 누르거나, 특정 방향으로 도구를 사용하는 상황에서도 같은 방식으로 확장할 수 있다.

 

현재 정리된 조작 방향

현재 플레이어 조작은 다음 방향으로 정리되고 있다.

상황  회전 기준
일반 이동 이동 입력 방향
입력 없음 마지막 바라본 방향 유지
우산으로 물 붓기 마우스로 피킹한 지점 방향
큰 방향 전환 회전 각도에 따라 이동량 감소

이 방식은 PC 조작뿐 아니라 모바일 조작까지 고려한 방향이다. 모바일에서는 마우스 방향을 항상 바라보게 하기 어렵기 때문에, 기본적으로는 왼손 조이스틱의 이동 방향을 바라보고, 특정 상호작용 중에만 오른쪽 버튼으로 방향을 override하는 구조가 더 적합하다고 판단했다.

마무리

이번 작업은 단순히 캐릭터가 이동 방향을 보게 만든다에서 끝나지 않았다. 이동 방식을 가속/감속 기반으로 바꾸고, 회전 중 발 밀림을 줄이고, 우산 시스템이 필요할 때 플레이어의 바라보는 방향을 잠시 가져갈 수 있도록 구조를 열어두었다.

아직 실제 애니메이션이 붙은 상태는 아니지만, 이후 캐릭터 모델과 애니메이션을 넣었을 때 덜 어색하게 이어질 수 있는 기반을 만든 셈이다.