사각형과 원의 충돌

MyEngine 버전을 ver 1.03으로 올렸다.

원과원의 충돌은 간단하다.
하지만 사각형과 원의 충돌은 간단 할 것 같지만 실제로 구현해보면 간단하지가 않다.
그 해법은 아래 사이트에 있다.

http://hq.scene.ro/blog/read/circle-box-intersection-revised/



그림처럼 4번 영역의 사각형을 기준으로 9개 영역으로 나눈다.
사각형과 원이 충돌하는 경우는 세가지 경우이다.

1. 원의 중심이 사각형에 포함되는 경우 (4번 영역)

원의 중심이 사각형 left, bottom보다 크고, right, top보다 작은지 검사한다.

2. 원의 중심이 사각형 밖의 모서리에 있는 경우 (0, 2, 6, 8번 영역)

원이 이 영역에 있을 때, 원에 가장 가까운 점은 사각형의 모서리이다.
사각형의 모서리가 원에 포함 되는지 검사한다.

3. 원의 중심이 사각형 변에 있는 경우 (1, 3, 5, 7번 영역)

x축이나 y축의 한축의 사각형과 원 사이의 길이가
x축이나 y축의 사각형 반지름과 원의 반지름보다 작으면 교차한다.

int MyRect::GetRectZone( float circleX, float circleY )

{

    int xZone = ( circleX <  min.x ) ? 0 :          

                ( circleX >  max.x ) ? 2 : 1;

    int yZone = ( circleY <  min.y ) ? 0 :          

                ( circleY >  max.y ) ? 2 : 1;

    int nZone = xZone + 3*yZone;

    return nZone;

}

 

bool MyRect::IntersectCircle( MyCircle& circle )

{

    bool collisionDetected = false;

    int  nZone = GetRectZone( circle.x, circle.y );

    MyVector2 box = GetCenter();

    float halfHeight = GetHeight();

    float halfWidth = GetWidth();

 

    switch (nZone )

    {

    // top, bottom 변의 영역에서, 원의 센터와 수직거리를 검사한다.

    case 1:

    case 7:

        {

            float distY = fabs( circle.y - box.y );

            if( distY <= ( circle.radius + halfHeight ) )

                collisionDetected = true;

        }

        break;

    // left, right 변의 영역에서. 원의 센터와 수평거리를 검사한다.

    case 3:

    case 5:

        {

            float distX = fabs( circle.x - box.x );

            if( distX <= ( circle.radius + halfWidth ) )

                collisionDetected = true;

        }

        break;

    // 사각형 영역의 내부

    case 4:

        collisionDetected = true;

        break;

    // 모서리 영역, 모서리가 원의 내부에 포함되는지 검사한다.

    default:

        {

            float cornerX = ( nZone == 0 || nZone == 6 ) ? box.x - halfWidth : box.x + halfWidth;

            float cornerY = ( nZone == 0 || nZone == 2 ) ? box.y - halfHeight : box.y + halfHeight;

            if( circle.IncludePoint( cornerX, cornerY ) )   

                collisionDetected = true;

        }

        break;

    }

 

    return collisionDetected;

}