내일배움캠프/TIL

내일배움캠프 17일차 TIL - Atan2

서보훈 2024. 10. 8. 20:37

개인적으로는 LookAt() 혹은 Euler 를 사용하여 타겟을 조준하는 방법만을 사용하였는데,

Atan 아크탄젠트를 사용해본적은 없어서 정리해보고자 합니다.

 

먼저 Euler 를 사용하여 대상을 바라보도록 만들경우 이러한 과정을 거칩니다.

//공격대상을 바라보도록 포탑 회전
protected void LockOn()
{
    //바라볼 방향벡터 얻기
    Vector3 dir = nowTarget.transform.position - transform.position;
    //Vector3 값을 Quaternion 값으로 변환
    Quaternion lookRotation = Quaternion.LookRotation(dir);
    //포탑을 천천히 회전시키기(타겟이 보이자 마자 모션없이 바로 보는것을 방지)
    Quaternion qRotation = Quaternion.Lerp(turretHead.rotation, lookRotation, Time.deltaTime * headRotateSpeed);
    //Quaternion 값을 Eular 값으로 변경
    Vector3 eAngle = qRotation.eulerAngles;
    //터렛의 Y축만 회전
    turretHead.rotation = Quaternion.Euler(0f, eAngle.y, 0f);
}

대상의 position 값에서 자신의 position 값을 빼주는것으로 대상을 향한 벡터값을 얻습니다.

//바라볼 방향벡터 얻기
Vector3 dir = nowTarget.transform.position - transform.position;

 

아래의 모습처럼 벡터의 x, y 값을 얻을 수 있습니다.

얻어준 벡터값을 Quaternion.LookRotation() 을 사용하여 쿼터리언 값으로 변환시켜줍니다.

이 쿼터리언 값이 회전의 목표가 됩니다.

//Vector3 값을 Quaternion 값으로 변환
Quaternion lookRotation = Quaternion.LookRotation(dir);

 

만들어준 값을 즉시 적용할경우 아무런 모션없이 즉시 대상을 바라보게됩니다.

만약 포탑등의 형태로 대상을 바라보는 모션이 필요할경우 Lerp를 사용하여 일정값만큼만 움직이도록 만들어줍니다.

//포탑을 천천히 회전시키기(타겟이 보이자 마자 모션없이 바로 보는것을 방지)
Quaternion qRotation = Quaternion.Lerp(turretHead.rotation, lookRotation, Time.deltaTime * headRotateSpeed);

 

이렇게 얻어준 쿼터리언값을 eulerAngles를 사용하여 Vecter3 값으로 변형시킨 뒤,

transform.rotation = Quaternion.Euler(Vector3) 의 형태로 사용하여 대상의 회전을 구현할 수 있습니다.

//Quaternion 값을 Eular 값으로 변경
Vector3 eAngle = qRotation.eulerAngles;
//터렛의 Y축만 회전
turretHead.rotation = Quaternion.Euler(0f, eAngle.y, 0f);

 

 

Atan2 를 사용할경우, 위와 같이 대상 사이의 거리를 빼서 Vector값을 얻은 뒤, 목표 회전값을 float 변수로 저장하게 됩니다.

//Vector2 direction = new Vector2(x, y) 를 사용할경우

float targetZ = Mathf.Atan2(direction.y , direction.x) * Mathf.Rad2Deg;

여기서 Mathf.Rad2Deg 가 사용되는데, 이는 라디안 단위인 약 57.29  (실제로는, 180 / 3.14 를 연산) 을 가지고 있습니다.

 

이 부분에 정확한 해석이 들어가면 수학적 접근이 들어가게 됩니다.

혹시라도 추가로 알기 원하신다면 각도 - 라디안 변환을 검색해보시는것을 추천합니다...

 

뭔가를 설명해 보려고 했지만, 실패했습니다.

 

여기서 얻은 float 값은 오른쪽을 보는것을 0도로 두고 -180º ~ +180º 으로 표현됩니다.

 

강의에서는 -90º ~ 90º 로 제한을 두어 회전값을 구하고, 제한값을 넘으면 좌우를 반전시키는 방식으로 조준을 구현하게 됩니다.

 

구해진 float 값을 transform.rotation = Quaternion.Euler(0, 0, z) 의 z 값에 입력하면, 회전을 구현할 수 있습니다.

 

 

글을 쓰면서 느낀것은 2D 형태의 게임을 제작할경우 세개의 축중 하나는 각도만을 구하는 축으로 사용되기 때문에 Atan을 통해 회전을 구현하기 쉽지만,

3D 형태의 경우 회전축이 매번 달라지며 복합적인 회전이 필요한 경우도 있기 때문에 위와 같은 방법을 사용하거나 LookAt() 함수를 사용하는것이 유리하다고 생각됩니다.