Right, then... I'll assume you know basic vector maths (dot products in particular... both how to calculate them and what they mean) and also how to perform a normal SAT test with polygons. Check the tutorial linked to earlier in the thread (and at the bottom of this post) for information about that. Not the best tutorial perhaps, but with some googling there should be no problem.
Here is some pseudo code describing how to do collision between convex polygons and circles:
Code:
bool CircleVsPolygonTest(circle circ, polygon poly)
{
/* First, make a poly vs poly test, treating the circle as an AABB with
* width == height == radius
*/
if(!PolyVsPolySATTest(circ, poly))
{
/* If no collision was detected in the simple alogirithm, there cannot have been one:
* that's because the aabb the circle was treated like is in fact its actual bounding
* box. So just return false here
*/
return false;
}
// Otherwise, we have to make som more tests
else
{
/* Basically we need to determine what feature of poly lies
* closest to circ. If it is an edge, then a collision is guarenteed,
* otherwise a last check is needed. So, how do we check if an edge or a point lies
* closest? Start with finding the point in poly that lies closest to circ's centre...
*/
int pointidx = poly.getClosestPointTo(circ.centre);
/* Next step is to check where circ's centre lies in relation to poly, specifically
* where it lies when considering the two edges of poly that include the point
* we just found.
*
*
* As the poly's verts are stored in the order they make up the edges,
* getting the two closest edges is easy
*/
Vector edge = normalize(poly.vert(pointidx-1)-poly.vert(pointidx));
/* Now, we project the circle's centre and the polygon to the 1d space defined by
* the edge's plane
*/
double circle_p = dotproduct(circ.centre, edge);
/* These are the largest and smallest values found by projecting all of
* the polygon's vertices
*/
double poly_start_p = poly.minProjection(edge);
double poly_end_p = poly.maxProjection(edge);
if(poly_start_p < circle_p && poly_end_p > circle_p)
{
/* The circle's centre lies closer to this edge than it does to the point,
* so there is no need to check anything else... the initial simple test was correct.
*/
return true;
}
// Get the other edge
edge = normalize(poly.vert(pointidx+1)-poly.vert(pointidx));
// More of the same as above...
circle_p = dotproduct(circ.centre, edge);
poly_start_p = poly.minProjection(edge);
poly_end_p = poly.maxProjection(edge);
if(poly_start_p < circle_p && poly_end_p > circle_p)
{
return true;
}
/* So... now we know that the feature of poly that lies closest to circ
* is the same point we found earlier. Now we just need to see if they collide
* on the plane described by the vector between circ's centre and that same point.
*/
edge = normalize(poly.vert(pointidx) - circ.centre);
// This time we project the entire circle
double circ_start_p = circ.minProjection(edge);
double circ_end_p = circ.maxProjection(edge);
poly_start_p = poly.minProjection(edge);
poly_end_p = poly.maxProjection(edge);
// Check if there is NOT a collision in 1d...
if(circ_start_p > poly_end_p || circ_end_p < poly_start_p)
return false;
// We have a collision
else
return true;
}
With the help of this tutorial, you should be able to figure the rest out yourself.
As far as I can tell, this should work for any convex polygon. I suppose it might work in 3d as well, though I've not made any tests in 3d, nor have I really thought about it.