AABB重叠的核心逻辑是x轴和y轴投影均不分离,即(a.max.x >= b.min.x) && (b.max.x >= a.min.x) && (a.max.y >= b.min.y) && (b.max.y >= a.min.y),该式基于分离轴定理,简洁高效且默认将边缘接触视为碰撞。
判断 AABB 重叠的核心逻辑是「分离轴不成立」
两个 AABB 不重叠,当且仅当在 x 轴或 y 轴上完全分离。所以只要在两个轴上都「没分离」,就一定重叠。这不是几何直觉,而是分离轴定理(SAT)在轴对齐情况下的极简退化——你不需要算投影、不用叉乘,只比四次大小。
常见错误是写成
这类混用大小关系的条件,容易漏掉边界相等(即边刚好贴合)是否算碰撞的语义问题。实际工程中,**边重合通常视为碰撞**(例如格子地图中角色贴墙应停止移动),所以要用 ≤ / ≥,而不是 。
正确判定 x 轴未分离:
y 轴同理:
两轴同时未分离才返回
;任一轴分离,立即返回
若使用浮点坐标,注意
或直接比较可能受精度影响,但 AABB 重叠判定本身对 eps 敏感度低,一般无需额外容差(除非你明确要求“间隙小于 0.001 才算碰”)
用结构体封装时,
和
的字段顺序不能反
很多人定义 AABB 为
,然后靠
/
是左下、
/
是宽高来推导 min/max。这没问题,但一旦和别人代码对接或调用第三方库(如 SDL_FRect、Box2D 的
),字段含义就容易错位。
更稳妥的做法是显式存
和
:
立即学习
“
C++免费学习笔记(深入)
”;
C知道
CSDN推出的一款AI技术问答工具
下载
这样判定函数清晰无歧义:
如果非要用
,务必统一约定:比如
是中心点,则
;如果是左上角,则
—— 混用会导致 y 轴判定恒错
OpenGL 坐标系(y 向上)和多数 2D 引擎(y 向下)不影响 AABB 逻辑,因为重叠只依赖相对大小,不依赖方向
性能关键:早退出 + 内联 + 避免分支预测失败
这个函数会被每帧调用成百上千次(比如粒子碰撞、UI 矩形裁剪),所以不能只图写得短。x 轴分离的概率通常高于 y 轴(尤其在横向滚动场景),把 x 轴判断放前面能更快拒绝。
用
(C++20)或编译器内置提示(如
)对「不重叠」分支做提示,但收益有限;优先保证逻辑清晰
必须声明为
或放在头文件里,避免函数调用开销
不要写成
—— 多一次取反、多一个临时变量,还掩盖了早退出意图
如果批量检测(如四叉树遍历),考虑 SIMD 对四个 AABB 同时做 x 轴比较,但单次判定没必要过早优化
容易被忽略的边界:空矩形与 NaN 坐标
没人会故意传空矩形,但构造函数出错、输入数据损坏、除零后赋值都可能导致
或出现
。此时上述判定会行为异常(
),导致本该碰撞的被跳过。
上线前加断言:
生产环境可加防御性检查:
空矩形(
)仍可参与判定:它退化为线段或点,只要另一矩形覆盖该点就算重叠
如果业务要求「面积为 0 不算碰撞」,需额外判断
,但这是业务逻辑,不是 AABB 数学定义
真正难处理的是跨坐标系拼接(比如 UI 层用像素坐标,物理层用米制单位),这时候光看 AABB 判定没用——得先做坐标转换。但那是另一个问题了。
if (a.min.x b.min.x && ...)a.min.x a.min.y truefalse==minmaxstruct AABB { float x, y, w, h; };xywhb2AABBminmaxstruct AABB {
float min_x, min_y;
float max_x, max_y;
};bool overlaps(const AABB& a, const AABB& b) {
return a.min_x <= b.max_x && b.min_x <= a.max_x &&
a.min_y <= b.max_y && b.min_y <= a.max_y;
}x,y,w,hx,ymin = x - w/2min_y = y - h[[likely]]__builtin_expectinlinereturn !(separated_on_x || separated_on_y);min_x > max_xNaNNaN 恒为 falseassert(a.min_x if (std::isnan(a.min_x) || std::isnan(b.max_x)) return false;min == max(a.max_x - a.min_x) > 0 && (a.max_y - a.min_y) > 0