내가 일하며 알게 된 프로그래밍
article thumbnail

게임에서 충돌 체크를 하는 방법은 여러가지가 있다.

물론 이 글에서 모든 충돌 방법을 설명하기는 어려울 것이고, 알고 있는 충돌 방법 이외에 다른 충돌 체크 방법도 있기에

모든 충돌 체크를 설명한다는 것은 불가능할 것이다.

가장 많이 쓰였던 혹은 많이 쓰이는 충돌 체크 방법들을 알아보자

 

픽셀 충돌

이미지들의 텍스쳐 픽셀 데이터를 통해 픽셀들이 동일한 위치에 존재하는지 체크 하는 방식이다.

포트리스나 웜즈 같은 게임이 픽셀 충돌을 이용하여 자연스러운 이동을 표현할 수 있다.

충돌 체크 코드는 비교적 단순하지만 단순한 for문 연산이기때문에 픽셀의 사이즈가 커질수록 연산 횟수가 증가한다.

private bool CheckPixelCollision(ObjectClass objectA, ObjectClass objectB)
{
    // 텍스처의 픽셀 데이터를 가져오기
    Color[] pixelsA = objectA.textureA.GetPixels();
    Color[] pixelsB = objectB.textureB.GetPixels();

    // 두 이미지가 겹치는 영역 계산
    Rect rectA = GetRect(objectA);
    Rect rectB = GetRect(objectB);

    int startX = Mathf.Max((int)rectA.x, (int)rectB.x);
    int startY = Mathf.Max((int)rectA.y, (int)rectB.y);
    int endX = Mathf.Min((int)(rectA.x + rectA.width), (int)(rectB.x + rectB.width));
    int endY = Mathf.Min((int)(rectA.y + rectA.height), (int)(rectB.y + rectB.height));

    // 겹치는 영역에서 각 픽셀 비교
    for (int x = startX; x < endX; x++)
    {
        for (int y = startY; y < endY; y++)
        {
            Color pixelA = pixelsA[x - (int)rectA.x + (y - (int)rectA.y) * textureA.width];
            Color pixelB = pixelsB[x - (int)rectB.x + (y - (int)rectB.y) * textureB.width];

            // 투명하지 않은 픽셀 간의 충돌 체크
            if (pixelA.a > 0 && pixelB.a > 0)
            {
                return true; // 충돌이 감지되었다면 true 반환
            }
        }
    }
    // 모든 픽셀이 충돌하지 않았다면 false 반환
    return false; 
}

위 예시 코드처럼 2개의 오브젝트의 위치값을 가져온 후
텍스쳐의 픽셀 사이즈만큼 반복을 하면서 알파값(투명값)을 제외하고 겹치는 부분이 있다면 충돌 처리를 하는 방식이다.

 

원 충돌

두 점을 기준으로 원을 그려 반지름의 값과 비교하여 충돌을 체크하는 방식이다.

피타고라스 방정식에서 배운 a^2 + b^2 = c^2

밑변제곱 + 높이제곱 = 빗변제곱을 사용하는 방식이다

점A와 점B의 x차이, y차이를 피타고라스 방정식으로 계산하여 얻은 빗변의 값이 원A,B의 반지름의 합보다 크다 혹은 작다를 이용한 방식이다

private bool CheckCircleCollision()
{
    //A,B의 위치값을 설정
    Vector2 A = Vector2.zero;
    Vector2 B = Vector2.zero;

    double x = Math.Pow(A.x - B.x, 2);
    double y = Math.Pow(A.y - B.y, 2);
    double h = Math.Sqrt(x * x + y * y);

    double radiusA = 0.5d; //A원의 반지름
    double radiusB = 0.5d; //B원의 반지름
    return h <= radiusA + radiusB;
}

예시코드처럼 A원과 B원의 x, y 값을 계산한 후 빗변 h의 길이를 구한 후

빗변의 길이가 A원과 B원의 반지름의 합보다 작다나 (같다면) 충돌 처리를 하는 방식이다.

 

AABB 충돌

Axis-Aligned Bounding Box의 약자로 오브젝트에 X축과 Y축의 변끼리 비교하여 충돌 체크를 하는 방식이다.

게임 활용 예시

bool CheckAABBCollision(Transform box1, Transform box2)
{
    Vector3 min1 = box1.GetComponent<Renderer>().bounds.min;
    Vector3 max1 = box1.GetComponent<Renderer>().bounds.max;

    Vector3 min2 = box2.GetComponent<Renderer>().bounds.min;
    Vector3 max2 = box2.GetComponent<Renderer>().bounds.max;

    // 두 AABB 박스가 충돌하는지 여부를 체크
    if (max1.x > min2.x && min1.x < max2.x &&
        max1.y > min2.y && min1.y < max2.y &&
        max1.z > min2.z && min1.z < max2.z)
    {
        return true; // 충돌
    }

    return false; // 충돌하지 않음
}

예시 코드에서 보면 바운드 박스를 이용하여 X축과 Y축만을 비교하여 충돌체크를 확인 할 수 있다.

 

OBB 충돌

OBB 박스

Oriented Bounding Box의 약자로 AABB충돌과는 다르게 회전을 허용하는 바운딩 박스로 계산한다.

AABB는 바운드 박스만을 기준으로 계산하기에 오브젝트가 회전이 발생할 경우 자연스러운 충돌체크를 하지 못한다.

즉 회전이 발생할 경우 AABB 박스의 크기가 변한다.

그래서 회전각까지 고려하여 체크하는 방식이다.

그림을 보면 각 오브젝트에 수직을 이루는 기준축을 설정 한 후

아래 기준축에서 초록색에 해당하는 겹치는 부분과 

위 기준축에서 빨간색에 해당하는 겹치지 않는 부분을 통해 체크하는 방식이다

자세한 설명은 아래 링크를 통해 상세하게 확인해보자.

http://www.gingaminga.com/Data/Note/oriented_bounding_boxes/

 

Object Oriented Bounding Box 를 이용한 Collision Detection

Object Oriented Bounding Box 를 이용한 Collision Detection 96419-044 안원선 출처; http://mimosa.snu.ac.kr/~rabbit2/ <목차> 소개글 이론 코드 다운로드 및 사용법 참고 문헌 웹페이지 다운로드 1. 소개글 지금까지 리

www.gingaminga.com

 

 

이렇게 4가지의 충돌 처리를 알아보았는데

이런 충돌 체크 방식 말고도 RayCasting 충돌, Mesh 충돌 등 여러 가지 충돌 방식이 존재한다.

모든 충돌 방식에는 각 장단점이 존재하기때문에

자신의 프로젝트에 맞는 효과적인 충돌 방법을 찾는 것 또한 중요한 일이다.

profile

내가 일하며 알게 된 프로그래밍

@CtrlVGames