Tell me more ×
Game Development Stack Exchange is a question and answer site for professional and independent game developers. It's 100% free, no registration required.

I have a non axis aligned rectangle, like a car, in my game. I have to check and resolve the collision between the rectangle and circle, which is stationary.

I have found lots of ways to determine the collision, but couldn't find anything on resolving it. It is clear that i have to push back the rectangle away if there is a collision, but I can't find a proper way.

Is there a way of handling and resolving the collision between a rectangle and a circle? Like an algorithm?

I am developing in c++.

share|improve this question
why don't you use already built physics engines like box2d? – Gajoo Aug 4 '12 at 0:18
1  
Look at this question: [stackoverflow.com/questions/2443845/… – ErikEsTT Aug 4 '12 at 6:33
I'm not sure, but I had an idea. Could testing the distance of the closest vertice of the rectangle to the circle work? It will move the rectangle away so that the distance is bigger than the radius of the circle... – user1509872 Aug 4 '12 at 9:37

2 Answers

up vote 0 down vote accepted

@ErikEsTT: the OP was specifically asking for more than a boolean "is intersecting", they need closest points or penetration depth or some other meaningful measurement of collision, not just a yes/no.

To answer the OP's question, circle-vs-rectangle can be implemented using a signed distance query between a rect and a circle. Probably the easiest thing to do is to transform the circle into the rect's local space (where it's an axis-aligned box) and then perform a point-vs-AABB signed distance query.

There is a brilliant (but quite confusing) signed box distance function here: http://www.iquilezles.org/www/articles/distfunctions/distfunctions.htm , or any good book (e.g RTCD or GeomTools) should have similar queries explained.

share|improve this answer

I took this answer, which is AABB - circle intersection and changed it into OBB - circle intersection and added compute of intersection point.

struct Vec2
{
    Vec2(): x( 0.0f ), y( 0.0f ) { }
    Vec2( float _x, float _y ): x( _x ), y( _y ) { }

    float x, y;
};

struct Box
{
    Vec2 Position, Size;
    float rotation;
};

struct Circle
{
    Vec2 Position;
    float radius;
};

Vec2 TranslatePointOnBox( const Vec2& BoxPosition, const Vec2& BoxRotation, const Vec2& Point, const Vec2& Sign )
{
    Vec2 LocalPoint( Point.x * Sign.x, Point.y * Sign.y );

    Vec2 WorldPoint;

    // rotate
    WorldPoint.x = LocalPoint.x * BoxRotation.x - LocalPoint.y * BoxRotation.y + BoxPosition.x;
    WorldPoint.y = LocalPoint.y * BoxRotation.x + LocalPoint.x * BoxRotation.y + BoxPosition.y;

    // translate
    WorldPoint.x += BoxPosition.x;
    WorldPoint.y += BoxPosition.y;

    return WorldPoint;
}

bool Itersects( const Circle& circle, const Box& box, Vec2& OutputPoint )
{
    Vec2 Diff1; // difference in world coord.
    Vec2 Diff2; // difference in local coord.
    Vec2 Rotation;
    Vec2 HalfSize;
    Vec2 Sign;  // for restoring intersection quadrant

    Diff1.x = circle.Position.x - box.Position.x;
    Diff1.y = circle.Position.y - box.Position.y;

    Rotation.x = cos( box.rotation );
    Rotation.y = sin( box.rotation );

    Diff2.x = Diff1.x * Rotation.x - Diff1.y * Rotation.y;
    Diff2.y = Diff1.y * Rotation.x + Diff1.x * Rotation.y;

    Sign.x = Diff2.x < 0.0f ? -1.0f : 1.0f;
    Sign.y = Diff2.y < 0.0f ? -1.0f : 1.0f;

    Diff2.x = abs( Diff2.x );
    Diff2.y = abs( Diff2.y );

    HalfSize.x = box.Size.x / 2.0f;
    HalfSize.y = box.Size.y / 2.0f;

    // intersection AABB - circle
    if( Diff2.x > HalfSize.x + circle.radius ||
        Diff2.y > HalfSize.y + circle.radius )
    {
        OutputPoint = Vec2( 0.0f, 0.0f );
        return false;
    }

    if( Diff2.x <= HalfSize.x )
    {
        OutputPoint = TranslatePointOnBox( box.Position, Rotation, Vec2( HalfSize.x, Diff2.y ), Sign );
        return true;
    }
    if( Diff2.y <= HalfSize.y )
    {
        OutputPoint = TranslatePointOnBox( box.Position, Rotation, Vec2( Diff2.x, HalfSize.y ), Sign );
        return true;
    }

    float CornerDistSquared =
        pow( Diff2.x - HalfSize.x, 2.0f ) +
        pow( Diff2.y - HalfSize.y, 2.0f );

    if( CornerDistSquared <= circle.radius * circle.radius )
    {
        OutputPoint = TranslatePointOnBox( box.Position, Rotation, HalfSize, Sign );
        return true;
    }
    else
    {
        OutputPoint = Vec2( 0.0f, 0.0f );
        return false;
    }
}

Note:

Intersection point is located on box surface, closest to circle center.

It is better to hold Box rotation in Vec2 rotation; instead float rotation;, so you don't need to compute sin/cos each intersection (compute only when rotation changes).

And you can omit OutputPoint = Vec2( 0.0f, 0.0f );, it return zero vector in no intersection cases.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.