0_1564473077975_1564473064137.jpg

先简单介绍下,左边是个圆,右边是个矩形(AABB)箱。AABB-AABB和圆-AABB都是常用的碰撞检测方法,这种算法比较简单高效,但是精度不高,因为碰撞箱与被包裹物体很难完全吻合,所以会导致实际还没碰撞的时候就检测到碰撞。


圆-AABB碰撞检测原理:

找到矩形与圆最近的点vP,vC - vP,如果小于或等于0则发生碰撞。


字母上方带一横的表示向量,我会在字母前用一个小写的v来表示向量。

坐标使用左上角为原点(0.0),还有一些参数没在图中标记出。
vec2:表示有x和y向量的分量(两个分量)。

圆的坐标原点为:vCirclePos [vec2类型]
矩形坐标原点:vRectanglePos [vec2类型]。
矩形向量:vRectangle {vec2类型}


参数介绍:

  • radius:圆的半径
  • vC:圆心,可以通过pCircle + radius计算出
  • half_width:矩形宽度的一半,vRectangle.x / 2
  • half_height:矩形高度的一半, vRectangle.y / 2
  • clamped.x:限制后的宽度
  • clamped.y: 限制后的高度
  • vB :矩形中心,vRectanglePos.x + half_width, vRectanglePos.y + half_height
  • vD:圆心与矩形中心的向量差,vD = vC - vB
  • vP:距离圆最近的点

其中clamped.x和clamped.y(clamped向量)是通过限制函数计算出来的,限制函数可以将vD限制在了矩形的4条边上,这样可以计算出矩形边上的哪个点与当前的圆是最近的。

常见的限制函数算法:

float clamp(float value, float min, float max){
    return std::max(min, std::min(max, value));
}

圆-AABB碰撞检测伪代码:

// 计算出圆心位置和矩形中心位置
vC = pCircle + radius;
half-width = vRectangle.x; / 2;   // 矩形半宽
half-height = vRectangle.y; / 2; // 矩形半高


// 计算圆心与矩形中心的向量差
vD = vC - vB;
// 通过限制函数计算出圆心到矩形最近点的向量差
// 如果以矩形中心为原点,左上角的向量就是(-half_width, -half_height);
// 同理右下角的向量就是(half_width, half_height);
// 这样可以把vD向量控制在由矩形中心到矩形边的长度,所以vP肯定会落在矩形边上
vD.x = clamp(vD.x,  -half_width, half_width);
vD.y = clamp(vD.y, -half_height, half_height);
// 使用矩形中心 + vD,得到距离最近的点vP
vP = vRectangle + vD;
// 最后计算出圆心到距离最近点vP的距离是否小于等于圆的半径radius
// 如果小于等于圆的半径则发生圆-AABB发生碰撞
difference = vP - vC;
if (length(difference) <= radius){
    // 碰撞处理
}