Take the 2-minute tour ×
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? –  Ali.S 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

3 Answers 3

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

I answered this over here, except the code is in Java (the math is easily translatable).

http://stackoverflow.com/questions/18704999/how-to-fix-circle-and-rectangle-overlap-in-collision-response/18790389#18790389

My solution handled axis-aligned boxes, but you can easily convert it to handle oriented boxes by rotating the circles current and future positions around the center of the rectangle until the rectangle is axis-aligned.

The aforementioned code accounts for high velocity moving circles, so that they can't pass through the rectangle and can't skip over corners.

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.