我已经成功实现了其他碰撞:AABB与AABB,Circle vs Circle,Poly与Poly等,但引入圆圈会带来奇怪的问题,即使理论上实现这些其他碰撞后应该是直接的。根据我的理解,AABB vs Circle实现应该像这样工作:
- 针对碰撞的X轴进行测试
- 针对碰撞的Y轴进行测试
- 测试从圆心的轴到AABB最近的顶点
醇>
我怀疑当我在第3步进行投影时可能会出现问题,但是我使用相同的投影技术进行聚合,这是我在这里用于AABB以及最小和最大投影的圆圈应该是圆圈的中心然后分别加上半径 - 至少我理解它。
我也添加了一些参考图片(黄色=无碰撞,红色=碰撞)
http://imgur.com/a/C2fDO
bool AABBCircleCollision(Point center1, int halfWidth1, int halfHeight1, Point center2, int radius2)
{
/***** TEST THE X-AXIS *****/
double min1, max1, min2, max2;
min1 = (center1.x - halfWidth1);
max1 = (center1.x + halfWidth1);
min2 = (center2.x - radius2);
max2 = (center2.x + radius2);
if(max1 <= min2 || max2 <= min1) {
return false;
}
// At this point it is intersecting on the X-axis, now find out if it is on the left or right
bool onRight;
if(min2 - max1 > min1 - max2)
onRight = true;
else
onRight = false;
/***** TEST THE Y-AXIS *****/
min1 = (center1.y - halfHeight1);
max1 = (center1.y + halfHeight1);
min2 = (center2.y - radius2);
max2 = (center2.y + radius2);
if(max1 <= min2 || max2 <= min1) {
return false;
}
// Like for the X-axis, find if the circle is above or below the AABB
bool onBottom;
if(min2 - max1 > min1 - max2)
onBottom = true;
else
onBottom = false;
/***** START TESTING THE AXIS BETWEEN CIRCLE'S CENTER AND CLOSEST VERTEX *****/
// Get the point of the AABB closest to the circles center
double vertX, vertY;
if(onRight)
vertX = center1.x + halfWidth1;
else
vertX = center1.x - halfWidth1;
if(onBottom)
vertY = center1.y + halfHeight1;
else
vertY = center1.y - halfHeight1;
// Get the axis vector between the closest point and the circles center
double axisX = center2.x - vertX;
double axisY = center2.y - vertY;
// Normalise it
double magV = sqrt(axisX * axisX + axisY * axisY);
axisX /= magV;
axisY /= magV;
// Project the AABB onto the axis
std::vector<Point> verts; // Here i'm creating the verts on the fly to see if this thing works. USE A BETTER WAY TO HANDLE THIS
verts.push_back(Point(center1.x - halfWidth1, center1.y - halfHeight1));
verts.push_back(Point(center1.x + halfWidth1, center1.y - halfHeight1));
verts.push_back(Point(center1.x + halfWidth1, center1.y + halfHeight1));
verts.push_back(Point(center1.x - halfWidth1, center1.y + halfHeight1));
min1 = std::numeric_limits<double>::max(), max1 = -min1; // Reset min and max values
for(int j=0; j < verts.size(); j++) {
double proj = (axisX * verts[j].x + axisY * verts[j].y);
min1 = std::min(proj, min1);
max1 = std::max(proj, max1);
}
// Project the circle onto the axis
min2 = axisX * (center2.x - radius2) + axisY * (center2.y - radius2);
max2 = axisX * (center2.x + radius2) + axisY * (center2.y + radius2);
printf("%f <= %f || %f <= %f\n", max1, min2, max2, min1);
if(max1 <= min2 || max2 <= min1) {
return false;
}
return true;
}