碰撞检测算法:圆-AABB



  • 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){
        // 碰撞处理
    }
    

Log in to reply