AABB碰撞检测的逻辑前提是两个矩形必须轴对齐,即边严格平行于坐标轴,否则结果不可靠;若矩形旋转或坐标系y轴方向不一致(如SDL向下、OpenGL向上),或用浮点直接判等,均会导致误判。

什么是AABB碰撞检测的逻辑前提
AABB(Axis-Aligned Bounding Box)要求两个矩形边必须与坐标轴平行,否则结果不可靠。如果你的矩形是旋转过的,rect1 和 rect2 的 x、y、width、height 值再怎么算,用AABB公式也会误判——它根本不处理角度。
常见错误现象:明明看着相交,isColliding() 却返回 false。十有八九是用了带旋转的矩形,或者坐标系原点理解反了(比如SDL或OpenGL中y轴朝下)。
- 确认两个矩形都未旋转,即四条边严格水平/垂直
- 统一坐标系:检查
y是否向下增长;若向下,需把top和bottom的比较逻辑反过来 - 避免用浮点数直接比较相等,尤其在边界刚好贴合时,建议用
std::abs(a - b)
C++中实现AABB碰撞判断的标准写法
核心思想是“分离轴定理”的简化:只要在x轴或y轴上两个矩形不重叠,就一定没碰撞。所以先写“不碰撞”的条件,再取反。
假设矩形结构体定义为:
立即学习“C++免费学习笔记(深入)”;
struct Rect {
float x, y; // 左上角坐标(y向下为正)
float width, height;
};那么碰撞判断函数应这样写:
bool isAABBColliding(const Rect& a, const Rect& b) {
if (a.x + a.width <= b.x || // a在b左边,无重叠
b.x + b.width <= a.x || // b在a左边
a.y + a.height <= b.y || // a在b上方(y向下)
b.y + b.height <= a.y) // b在a上方
return false;
return true;
}注意:a.x + a.width 是右边界,a.y + a.height 是底边界(y向下)。如果y向上为正(如数学坐标系),要把后两行的 <= 改成 >=,并把 a.y 理解为底边而非顶边。
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
容易被忽略的边界情况处理
AABB默认采用“边接触即碰撞”,但实际项目里常需要明确是否包含边界。比如UI按钮悬停检测,可能希望边挨着不算触发;而物理引擎则通常要包含。
关键差异在比较运算符:
- 用
<和>:严格内部重叠,边接触返回false - 用
<=和>=:边接触即判定为碰撞(更常用) - 如果矩形用
left/right/top/bottom字段存储,直接比较left < right2 && right > left2 && top < bottom2 && bottom > top2更清晰,也更少出错
性能上毫无差别,但可读性差的写法(比如嵌套三目运算)会让后续维护者花三分钟看懂一行代码。
在SFML/SDL等库中调用时的注意事项
这些库的矩形类型(如 sf::FloatRect 或 SDL_Rect)自带 intersects() 方法,但行为未必一致:
-
sf::FloatRect::intersects()使用<=判定,边接触算碰撞 -
SDL_HasIntersection()对SDL_Rect使用整数截断,若传入负坐标或宽高为0,可能返回意外结果 - 不要直接拿
SDL_Rect的x/y/w/h去喂自定义AABB函数——它的w和h可能是0或负值,需先做abs()或校验
最稳妥的做法:从库对象提取数据后,先规整化(确保 width > 0、height > 0),再进你的 isAABBColliding()。
边界对齐、坐标方向、浮点精度——这三个点漏掉任何一个,都可能让看似简单的矩形碰撞在某台机器上偶尔失效。

















