[게임수학][Unity] 부채꼴 안의 적 판별

WestCoast·2022년 5월 11일
0

게임수학

목록 보기
1/1

1. 목표


  • 예를 들어 플레이어가 부채꼴 모양의 스킬을 사용했을 때, 적이 그 스킬의 범위 안에 들어오는지 판단하기 위한 방법
  • 벡터의 내적을 응용해서 부채꼴 안에 타겟 오브젝트가 들어오는지 아닌지를 판단

Youtube - 부채꼴 안의 적 판별

유튜브 링크로 결과물을 올려두었으니 먼저 영상을 보고 포스팅을 읽어보는 것을 추천합니다.


2. 초기값


아래 요소만 주어지면 부채꼴 내부에 적이 있는지 판별이 가능하다.

  1. 나의 좌표
  2. 내가 보는 방향 벡터
  3. 타겟의 좌표
  4. 부채꼴의 반지름
  5. 부채꼴의 사잇각

3. 간략한 순서


  1. 타겟과 나 사이의 벡터(A)를 구한다.
  2. A의 크기(길이)와 부채꼴의 반지름을 비교한다.
  3. 만약 A의 크기가 부채꼴의 반지름보다 작다면 부채꼴의 사잇각에 들어오는지 계산한다.
  4. 모두 참일 때만 부채꼴의 색상을 바꿔준다.

4. 벡터의 내적


벡터의 내적은 위와 같이 두가지 방법으로 구할 수 있다.
여기서는 두 방법을 모두 사용하게 된다.
1. '타겟-나 벡터'와 '내 정면 벡터'를 내적하기 위해
2. 내적 결과에 cos의 역을 취해서 theta를 구하기 위해

// '타겟-나 벡터'와 '내 정면 벡터'를 내적
float dot = Vector3.Dot(interV.normalized, transform.forward);
// 두 벡터 모두 단위 벡터이므로 내적 결과에 cos의 역을 취해서 theta를 구함
float theta = Mathf.Acos(dot);

5. 내 정면 벡터와 타겟-나 벡터를 내적하는 이유


A 벡터와 B 벡터의 사잇각이 '부채꼴의 사잇각 / 2'보다 작거나 같은지 판별하기 위해. 만약 아니라면 적이 범위에 들어오지 않은 것임.

여기서 A 벡터는 타겟의 좌표 - 내 좌표로 구할 수 있다.

Vector3 interV = target.position - transform.position;

B 벡터는 transform.forward 로 구할 수 있다. (정확히 말하면 B벡터의 normalization)


6. 내적의 활용


7. 코드

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;  // OnDrawGizmos

public class CircularSector : MonoBehaviour
{
    public Transform target;    // 부채꼴에 포함되는지 판별할 타겟
    public float angleRange = 30f;
    public float radius = 3f;

    Color _blue = new Color(0f, 0f, 1f, 0.2f);
    Color _red = new Color(1f, 0f, 0f, 0.2f);

    bool isCollision = false;

    void Update()
    {
        Vector3 interV = target.position - transform.position;

        // target과 나 사이의 거리가 radius 보다 작다면
        if (interV.magnitude <= radius)
        {
            // '타겟-나 벡터'와 '내 정면 벡터'를 내적
            float dot = Vector3.Dot(interV.normalized, transform.forward);
            // 두 벡터 모두 단위 벡터이므로 내적 결과에 cos의 역을 취해서 theta를 구함
            float theta = Mathf.Acos(dot);
            // angleRange와 비교하기 위해 degree로 변환
            float degree = Mathf.Rad2Deg * theta;

            // 시야각 판별
            if (degree <= angleRange / 2f)
                isCollision = true;
            else
                isCollision = false;

        }
        else
            isCollision = false;
    }
	
    // 유니티 에디터에 부채꼴을 그려줄 메소드
    private void OnDrawGizmos()
    {
        Handles.color = isCollision ? _red : _blue;
        // DrawSolidArc(시작점, 노멀벡터(법선벡터), 그려줄 방향 벡터, 각도, 반지름)
        Handles.DrawSolidArc(transform.position, Vector3.up, transform.forward, angleRange / 2, radius);
        Handles.DrawSolidArc(transform.position, Vector3.up, transform.forward, -angleRange / 2, radius);
    }
}

참고한 글

3. 부채꼴 충돌

이 글의 코드도 한 번 보는 것을 추천한다. 나는 라디안을 degree로 바꾸어서 좀 더 angle과의 연관성을 이해하기 쉽게 하기 위해 acos을 한 번 하는 과정을 더 거쳤지만 링크에서는 그 과정을 생략하고 라디안끼리의 비교로 판단했다.

profile
게임... 만들지 않겠는가..

3개의 댓글

comment-user-thumbnail
2022년 12월 1일

안녕하세요 글 너무 잘 봤습니다
부채꼴의 사이각 /2 보다 작거나 같다는 부분이 이해가 잘 안가는데 설명해주실 수 있을까요?

2개의 답글