[Unity] 타겟을 향한 오브젝트 회전, 캐릭터 컨트롤러 이동(transform.rotation, Quaternion.Lerp, Quaternion.LookRotation)

728x90

타겟 쪽으로 회전 및 이동

Enemy 오브젝트가 Player 오브젝트를 바라보도록 회전하고, 큐브 위에 올라가 있는 Player를 향해 자연스럽게 이동 및 회전할 수 있는 코드를 구현하였다.

private void Move()
{
	// 타겟 쪽으로 이동
	Vector3 dir = target.position - transform.position;
    dir.Normalize();
    dir.y = 0;
    
    // 타겟 쪽으로 회전
    // transform.LookAt(target);
    // transform.forward = Vector3.Lerp(transform.forward, dir, 5 * Time.deltaTime);
    transform.rotation = Quaternion.Lerp(transform.rotation, Quaternion.LookRotation(dir), 5 * Time.deltaTime);
    
    // 이동
    // cc.Move(dir * speed * Time.deltaTime);
    cc.SimpleMove(dir * speed);
}

Enemy 오브젝트가 Player 오브젝트(타겟)를 바라보도록 하는 코드는 대표적으로 다음 3가지가 있다.

transform.LookAt(target);
transform.forward = Vector3.Lerp(transform.forward, dir, 5 * Time.deltaTime);
transform.rotation = Quaternion.Lerp(transform.rotation, Quaternion.LookRotation(dir), 5 * Time.deltaTime);

유니티에서 제공하는 transform.LookAt() 함수를 사용하면 매우 간단하게 동작할 수 있다. 하지만 LookAt() 함수는 오브젝트가 확확 돌아가는 문제가 있다. 물론 그래도 되는 상황이라면 사용해도 상관 없지만 자연스러운 회전이 필요할 경우 Lerp() 함수를 응용해서 사용해야 한다.

 

transform.forward = Vector3.Lerp(transform.forward, dir, 5 * Time.deltaTime);

transform.forward 방향으로 회전 시 Lerp 함수를 사용하면 타겟의 위치에 따라 이상하게 회전할 수 있다. 해당 오류는 두 오브젝트가 서로 동일 선상(x좌표 / z좌표)에 위치했을 때 주로 발생한다. 해당 오류가 발생하는 이유는 짐벌락(?) 때문이다.

 

transform.rotation = Quaternion.Lerp(transform.rotation, Quaternion.LookRotation(dir), 5 * Time.deltaTime);

Vector3.forward를 사용했을 때 발생하는 회전 오류는 Quaternion 4원수 회전을 통해 해결해 줄 수 있다.

 

오브젝트 회전은 매우 민감(?)하기 때문에 또 다른 상황에서 문제가 발생할 수 있다. 만약 타겟 오브젝트가 큐브 위에 올라와 있다면(y좌표가 다른 경우) 회전은 정상적으로 하되, 중력이 적용되지 않기 때문에 공중 부양하는 오류 움직임을 보여준다. 유니티 Character Controller에서는 따로 rigidbody 컴포넌트를 붙여주지 않고 중력을 부여하는 cc.SimpleMove()라는 함수를 제공하고 있다. 여기서는 Time.deltaTime을 곱해주지 않아도 된다.

 cc.SimpleMove(dir * speed);

하지만 오브젝트가 계속 눕는 듯한 오류 움직임이 발생했다. 해당 문제는 rotation의 y값이 내부적으로 Time.deltaTime으로 계속 곱해지기 때문에 사선으로 눕는 듯한 오류 움직임이 생기는 것이다. 이런 경우 dir.y 값을 0으로 부여하므로서 쉽게 해결해주면 된다.

dir.y = 0;

 

728x90