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轴上两个矩形不重叠,就一定没碰撞。所以先写“不碰撞”的条件,再取反。
假设矩形结构体定义为:
struct Rect {
float x, y; // 左上角坐标(y向下为正)
float width, height;
};
那么碰撞判断函数应这样写:
bool isAABBColliding(const Rect& a, const Rect& b) {
if (a.x + a.width <p>注意:<code>a.x + a.width</code> 是右边界,<code>a.y + a.height</code> 是底边界(y向下)。如果y向上为正(如数学坐标系),要把后两行的 <code> 改成 <code>>=</code>,并把 <code>a.y</code> 理解为底边而非顶边。</code></p><div class="aritcle_card flexRow artxards">
<div class="artcardd flexRow">
<a class="aritcle_card_img" rel="nofollow" href="/xiazai/skill5502" title="C++ Code Review Master"><img
src="https://img.php.cn/upload/skill/000/000/081/179051228971575.jpg" alt="C++ Code Review Master" onerror="this.onerror='';this.src='/static/lhimages/moren/morentu.png'" ></a>
<div class="aritcle_card_info flexColumn">
<a rel="nofollow" href="/xiazai/skill5502" title="C++ Code Review Master" class="overflowclass">C++ Code Review Master</a>
<p class="overflowclass">组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。</p>
</div>
<a rel="nofollow" href="/xiazai/skill5502" title="C++ Code Review Master" class="aritcle_card_btn flexRow flexcenter"><b></b><span>下载</span>
</a>
</div>
</div><h3>容易被忽略的边界情况处理</h3><p>AABB默认采用“边接触即碰撞”,但实际项目里常需要明确是否包含边界。比如UI按钮悬停检测,可能希望边挨着不算触发;而物理引擎则通常要包含。</p><p>关键差异在比较运算符:</p>
- 用
和 <code>>:严格内部重叠,边接触返回false - 用
和 <code>>=:边接触即判定为碰撞(更常用) - 如果矩形用
left/right/top/bottom字段存储,直接比较left left2 && top 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()。
边界对齐、坐标方向、浮点精度——这三个点漏掉任何一个,都可能让看似简单的矩形碰撞在某台机器上偶尔失效。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!










