유니티2D 입문 정리 6 - 2D 기초 8강 조준(Aim) 시스템

woollim·2024년 10월 8일
0

1. 핵심 내용

○ 회전의 수학, 쿼터니언(Quaternion)

  • 유니티 인스펙터 창에서 나오는 회전은 Vector3로 표현되고,
    이런 방법을 오일러각(Euler Angle)이라고 함.
    하지만, 시중의 많은 3D 소프트웨어는 내부적으로 쿼터니언을 사용함
  • 쿼터니언을 사용할 시 짐벌 락(Gimbal Lock) 문제를 피할 수 있음.
    • 짐벌 락(Gimbal Lock) : 극단적인 각도로 회전할 경우 한 축으로의 회전을 잃어버리는 것
  • 수학적으로는 4차원 복소수를 이용한 회전 표현 방법.
    (x, y, z, w) 형태로 표현함
    !! 그렇다고 직접 x, y, z, w 값을 조정할 생각은 하면 안 됨
  • 직접 값을 변경하거나 계산하는 대신, Unity의 내장 함수를 사용하는 것이 좋음.
    (예: Quaternion.Euler, Quaternion.LookRotation, Quaternion.Slerp 등)
  • 쿼터니언은 애초에 직관적인 수체계를 사용하지 않음. 직접 값을 적용하려면, Quaternion.Identity (회전이 없는 상태를 나타내는 쿼터니언)만 사용해야 함

○ 쿼터니언과 함께 사용하는 주요 메소드

  • Quaternion.Euler : 오일러각을 쿼터니언으로 변경할 수 있음 (Quaternion.Euler(0f, 0f, 90f) → Quaternion으로 변환)
  • Quaternion.LookRotation : 머리를 회전하는 것처럼, 앞과 위를 특정한 방향으로 하는 회전 쿼터니언을 만듬
  • Quaternion.Slerp : 쿼터니언과 다른 쿼터니언 사이에 내분점을 알 수 있음. 구형 보간(Spherical Linear Interpolation)기법을 활용해서 쿼터니언에 쓰면 더 정확
    (두 쿼터니언 Q1, Q2가 있을 때 30% 지점은 어디일까? 이런 문제를 풀 때 유용)

○ 삼각함수 기초

  • 삼각함수 기초
    • 삼각함수는 각도를 통해 삼각형들의 각 변의 비율을 알아낼 수 있는 함수
    • 기본적인 삼각함수로 사인(sin), 코사인(cos), 탄젠트(tan)이 있음
  • 사인, 코사인, 탄젠트의 정의
    • sin = 높이/빗변 = b/a
    • cos = 밑변/빗변 = c/a
    • tan = 높이/밑변 = b/c
  • 요약 : 삼각함수는 비율을 알기 위해 각도 비율을 구하는 함수, 탄젠트(tan)는 그중에서도 밑변과 높이의 비율

○ 아크탄젠트 (ArcTangent)

  • 각도 -> 비율, 삼각함수는 각도를 알면 비율을 알 수 있음.
    좌표 -> 각도, 이번에 하고 싶은것은 좌표를 알면 각도가 몇도인지 알 고 싶음.
    비율 -> 각도, 아크 탄젠트는 비율을 알면 각도를 알 수 있음

  • 삼각함수에서 아크(arc)-가 붙으면 삼각함수의 역함수인 역삼각함수를 말함.
    각도->비율이었던게 비율->각도 가 됨👍
    즉, 아크탄젠트 함수는 삼각함수인 탄젠트의 역함수. 가로와 세로의 비에 따른 각도를 계산하는 데 사용

  • 2D에서 점 또는 벡터에 대한 각도를 찾는 데 아크탄젠트 함수가 종종 사용됨

  • 비율말고도 x, y자체가 양수인지 음수인지를 통해 360도를 다 구분해낼 수 있게 함

    • 원래는 x, y가 같은 부호이지만 둘다 양수, 둘다 음수이거나 x, y가 다른 부호이지만 x가 음수이거나 y가 음수인 상황 때문에 아크탄젠트로는 180도 각도 범위에서만 알아낼 수 있음
  • 이러한 구현을 개발자들은 Atan2라고 이름 붙이고, 밑변 / 높이였던 탄젠트의 기본 개념을 적용해 y, x순으로 인수를 넣음

  • 이를 통해 점 (x, y)에서, Math.Atan2(y, x) 함수를 사용하여 벡터가 x축과 이루는 각도를 [π,π][-\pi , \pi]까지의 값으로 얻을 수 있음
    (각도를 π\pi가 180도가 되도록 표현하는 방법을 호도법, 그리고 그 단위를 라디안이라고 부릅니다.)

  • Mathf.Rad2Deg = 180 / 3.14 가 이미 계산되어있음😥

  • Atan2를 활용해서 객체가 특정 방향을 향하도록 만들거나 두 점 사이의 각도를 계산할 때 유용함

- 요약 : Atan2는 각도를 알기 위해 y와 x의 비율을 통해 각을 알아내는 함수이고, [π,π][-\pi,\pi]범위에서 결과가 나옴


2. 마우스를 따라 회전하는 무기 만들기

○ 오브젝트 준비하기




○ TopDownAimRotation 만들기

  • TopDownController OnLookEvent에 등록할 메소드를 구현
    • 🤷‍♂️그럼 등록이 안되었는데 지금까지 오류가 안난 이유
      Action.Invoke()는 delegate가 비어있을 때는 별도의 호출을 하지 않는다는 의미.
      지금까지는 등록되어 있는 메소드가 없었기 때문에 무시하고 지나가게 됨.
  • 아크 탄젠트를 이용해 각도를 구함
public class TopDownAimRotation : MonoBehaviour
{
    [SerializeField] private SpriteRenderer armRenderer;
    [SerializeField] private Transform armPivot;

    [SerializeField] private SpriteRenderer characterRenderer;

    private TopDownController controller;

    private void Awake()
    {
        controller = GetComponent<TopDownController>();
    }

    private void Start()
    {
        // 마우스의 위치가 들어오는 OnLookEvent에 등록하는 것
        // 마우스의 위치를 받아서 팔을 돌리는 데 활용할 것임.
        controller.OnLookEvent += OnAim;
    }

    private void OnAim(Vector2 direction)
    {
        // OnLook
        RotateArm(direction);
    }

    private void RotateArm(Vector2 direction)
    {
        // Atan2는 직각삼각형이 있다고 할 때 세로가 y, 가로가 x일 때 그 각도를 라디안 [-Pi,Pi]로 나타내는 함수임
        // 라디안의 -Pi는 -180도, Pi는 180도 이므로 Mathf.Rad2Deg는 약 57.29임 (180 / 3.14)

        float rotZ = Mathf.Atan2(direction.y, direction.x) * Mathf.Rad2Deg;
        // 오일러에 넣어야 하므로 디그리로 변경해야 함
        // Atan2이므로 매개변수는 y x 순이어야함
        // 캐릭터에서 마우스를 바라보는 각도를 얻음
        // 좌표(y, x) -> 라디안 -> 각도

        // [1. 캐릭터 뒤집기]
        // 이때 각도는 오른쪽(1,0 방향)이 0도이므로,
        // -90~90도에서는 오른쪽을 바라보는 게 맞지만, -90도 미만 90도 초과라면 왼쪽을 바라보는 것임.
        characterRenderer.flipX = Mathf.Abs(rotZ) > 90f;
        // 절대값이 90도 보다 크면 플립
        // 왼쪽 구간에 있으면 뒤집어라

        // [2. 팔 돌리기]
        // 팔을 돌릴 때는 나온 각도를 그대로 적용하는데, 이때 유니티 내부에서 사용하는 쿼터니언으로 변환한다.
        // 쿼터니으로 변형하는 방법 두 가지
        // 1) Vector3를 Quaternion으로 변환해서 넣는 방법
        //    Quaternion.Euler(x 회전, y 회전, z 회전) : 오일러 각 기준으로 값을 넣으면 쿼터니언으로 변환됨
        // 2) eulerAngles를 통해 자동으로 변환되게 하는 방법 - rotation이랑 비슷하게 변환이 되어서 들어간다고 생각하면 됩니다.
        //    Transform.eulerAngles을 변경
        armPivot.rotation = Quaternion.Euler(0, 0, rotZ); // z축으로 회전해야함
        // (2번 방법으로 하면) armPivot.eulerAngles = new Vector3(0, 0, rotZ);
        // Quaternion.Euler를 이용해 각도를 지정해줌
    }
}


마우스 방향을 따라 플립과 활 방향 전환이 된다

0개의 댓글