9
votes

Is there a way in Libgdx to verify a collision between a Polygon and a Circle?

I saw the Intersector class but only found collision test for Circle and Rectangle. What about any other Polygon?

If I need to do it manually, what's the best way to do that using Libgdx?

3

3 Answers

13
votes

Sadly I don't have enough reputation to comment so I'm adding this as another answer instead...

Cristiano's excellent answer works for checking that the circle overlaps one of the line segments of the polygon, however it doesn't check for the more unusual case of the circle being fully contained inside the polygon, which could happen if a small fast moving circle collided with a large polygon.

I've repasted Cristiano's code below with a small change to fix the issue...

public static boolean overlaps(Polygon polygon, Circle circle) {
    float []vertices=polygon.getTransformedVertices();
    Vector2 center=new Vector2(circle.x, circle.y);
    float squareRadius=circle.radius*circle.radius;
    for (int i=0;i<vertices.length;i+=2){
        if (i==0){
            if (Intersector.intersectSegmentCircle(new Vector2(vertices[vertices.length - 2], vertices[vertices.length - 1]), new Vector2(vertices[i], vertices[i + 1]), center, squareRadius))
                return true;
        } else {
            if (Intersector.intersectSegmentCircle(new Vector2(vertices[i-2], vertices[i-1]), new Vector2(vertices[i], vertices[i+1]), center, squareRadius))
                return true;
        }
    }
    return polygon.contains(circle.x, circle.y);
}
12
votes

So, I managed to create a collision test method between a Circle and a Polygon. At least, it works for me.

Here's the code:

public boolean overlaps(Polygon polygon, Circle circle) {
    float []vertices=polygon.getTransformedVertices();
    Vector2 center=new Vector2(circle.x, circle.y);
    float squareRadius=circle.radius*circle.radius;
    for (int i=0;i<vertices.length;i+=2){
        if (i==0){
            if (Intersector.intersectSegmentCircle(new Vector2(vertices[vertices.length-2], vertices[vertices.length-1]), new Vector2(vertices[i], vertices[i+1]), center, squareRadius))
                return true;
        } else {
            if (Intersector.intersectSegmentCircle(new Vector2(vertices[i-2], vertices[i-1]), new Vector2(vertices[i], vertices[i+1]), center, squareRadius))
                return true;
        }
    }
    return false;
}
0
votes

...and to follow up on Phil Anderson's excellent answer, here's my version which simply avoids creating new Vector2s every check and instead re-uses static instances of Vector2.

public class PolygonUtil {

static final Vector2 center = new Vector2();
static final Vector2 vec1 = new Vector2();
static final Vector2 vec2 = new Vector2();

public static boolean overlaps(Polygon polygon, Circle circle) {
    float []vertices=polygon.getTransformedVertices();
    center.set(circle.x, circle.y);
    float squareRadius=circle.radius*circle.radius;
    for (int i=0;i<vertices.length;i+=2){
        if (i==0){
            if (Intersector.intersectSegmentCircle(vec1.set(vertices[vertices.length - 2], vertices[vertices.length - 1]),
                    vec2.set(vertices[i], vertices[i + 1]), center, squareRadius))
                return true;
        } else {
            if (Intersector.intersectSegmentCircle(vec1.set(vertices[i-2], vertices[i-1]), vec2.set(vertices[i], vertices[i+1]), center, squareRadius))
                return true;
        }
    }
    return polygon.contains(circle.x, circle.y);
}

}