스파르타 게임개발종합반(Unity)/TIL - 본캠프 매일 공부 기록

2024.05.20 TIL - 내적계산으로 시야각 계산, Physics2D.CircleCastAll, Vector2.Dot

테크러너 2024. 5. 20.

 

 

    [SerializeField] private float fov = 45f; // 시야각
    [SerializeField] private float radius = 10f; // 반지름
    private float alertThreshold; // Threshold가 문턱이라는 뜻
    private void Start()
    {
        animator = GetComponent<Animator>();
        // FOV를 라디안으로 변환하고 코사인 값을 계산
        alertThreshold = Mathf.Cos(fov * Mathf.Deg2Rad / 2f); // 좌우 fov(시야각)의 절반 -> 나누기 2f
    }

    private void Update()
    {
        CheckAlert();
    }

    private void CheckAlert()
    {
        int layerMask = LayerMask.GetMask("Aestroid");
        
        var hits = Physics2D.CircleCastAll(transform.position, radius, Vector2.up, 0f, layerMask);

        bool needAlert = false;
        foreach (var hit in hits)
        {
            Vector2 directionToTarget = (hit.transform.position - transform.position).normalized;
            float cos = Vector2.Dot(directionToTarget, transform.up.normalized);
            if (cos >= alertThreshold)
            {
                needAlert = true; // 더이상 검사안하고 루프 종료
                break;
            }
        }
        animator.SetBool(blinking, needAlert);
    }

전체코드는 위와 같다. 하나씩 살펴보겠다.

 

        // FOV를 라디안으로 변환하고 코사인 값을 계산
        alertThreshold = Mathf.Cos(fov * Mathf.Deg2Rad / 2f); // 좌우 fov(시야각)의 절반 -> 나누기 2f

`fov`는 시야각으로 `45도`로 설정했다.

`Mathf.Deg2Rad`을 곱해서 `라디안`으로 변환했다.

`2f`로 나눠준 이유는 시야각이 45도인데 2로 안나눠주면 왼쪽 45도, 오른쪽 45도로 90도의 시야각을 가지기 때문이다.

 

왜 `Cos`일까?

시야각을 표현하기 위해서는 내가 바라보고 있는 `transform.up` 벡터와 내 주변에 있는 객체 방향의 벡터, 두 벡터 간의 각도내적을 통해 계산하기 위해서다.

두 벡터를 내적했을 때 0이 되면 두 벡터는 직각을 이루고 있는 것이다.

그래서 처음에 시야각 45도의 cos값을 알아두는 것이다.

 

이제 `CheckAlert()`로 가보겠다.

        int layerMask = LayerMask.GetMask("Aestroid");
        
        var hits = Physics2D.CircleCastAll(transform.position, radius, Vector2.up, 0f, layerMask);

레이어마스크는 충돌할 소행성의 레이어로 설정했다.

`Physics2D.CircleCastAll`는 이름에서 알다시피 원형 영역내의 객체를 탐지할 수 있다.

매개변수는 (원형 영역의 시작 위치, 반지름, 원의 영역이 확장되는 방향, 원의 영역 확장의 최대 거리, 충돌 감지할 레이어)이다.

여기서 원의 영역 확장의 최대거리가 `0f`인데 이 의미는 단순히 원 영역 내의 충돌만 감지한다는 것이다.

 

Vector2 directionToTarget = (hit.transform.position - transform.position).normalized;

A에서 B로 가는 벡터를 구할 때 A-B가 아니라 B-A를 해야한다. 위의 코드는 그 의미이다.

 

float cos = Vector2.Dot(directionToTarget, transform.up.normalized);

이 코드가 내적계산이다. 두 벡터간의 각도를 구한다.

반응형

댓글