快速判断两个AABB是否相交:只需检查x、y(及z)轴投影是否同时重叠;任一轴分离(如a.max.x < b.min.x)即不相交,逻辑更安全可靠。

怎么快速判断两个 AABB 是否相交
两个 AABB(Axis-Aligned Bounding Box)是否碰撞,本质是判断它们在 x 和 y(以及 z,若为 3D)三个轴上投影是否同时重叠。只要有一个轴不重叠,就一定没碰撞 —— 这是分离轴定理(SAT)在轴对齐情况下的最简应用。
二维下只需检查两组区间是否都相交:rect1.x 与 rect1.x + rect1.width 构成的 x 区间,和 rect2.x 与 rect2.x + rect2.width 的 x 区间;y 方向同理。
- 别用中心点加半宽/半高去算 —— 容易因浮点误差或负尺寸出错,直接用左边界+宽更稳
- 注意:AABB 通常定义为
left,top,width,height,但有些库用min/max坐标(如min.x,max.x),此时判断更直白:! (a.max.x < b.min.x || a.max.y < b.min.y || b.max.x < a.min.x || b.max.y < a.min.y) - 如果矩形可能宽/高为负(比如由鼠标拖拽生成,未归一化),先调用
std::minmax对角点做归一化再判断,否则结果不可靠
为什么用 “不相交” 条件写判据更安全
主流实现都写成「若分离则返回 false」,而不是「若相交则返回 true」,因为分离条件逻辑更少、分支更清晰、不易漏边。
例如,x 轴分离的充要条件是:rect1.right < rect2.left || rect2.right < rect1.left(其中 right = left + width)。y 轴同理。只要任一轴分离,就无碰撞。
立即学习“C++免费学习笔记(深入)”;
- 错误写法:
if (x_overlap && y_overlap) return true;—— 看似自然,但x_overlap自身容易写反(比如把>=写成>),而分离式只涉及<,语义明确 - 浮点场景下,用
<=判分离边界(如a.max.x <= b.min.x)比用>更利于控制接触判定的包容性 - 若需支持“边缘接触即算碰撞”,所有比较符统一用
<=或>=;若需“严格重叠”,才用</>
C++ 实现中 struct 成员顺序和内存布局的影响
AABB 结构体若用于高频碰撞检测(比如每帧上万次),成员排列顺序会影响缓存友好性。x 和 y 相关字段尽量连续,避免跨 cache line 读取。
典型高效布局:
struct AABB {
float left, bottom; // 共享 cache line
float width, height;
};而非:
struct AABB {
float left, width, right; // right 是冗余字段,且分散
float top, height, bottom;
};- 别存
right和bottom—— 它们可即时计算,还浪费空间、破坏 locality - 若用 SIMD 批量检测(如 AVX 处理 8 个 AABB),建议结构体按 AoS→SoA 拆解,但单次判断仍推荐紧凑 AoS
- 对齐方面:
alignas(16)对 float4 友好,但纯 AABB 四 float 已天然满足 16 字节对齐,无需额外修饰
碰撞后求重叠区域(Intersect Rectangle)的常见陷阱
很多需求不止要 bool 判定,还要知道重叠部分的坐标(比如裁剪、响应偏移、物理冲量计算)。这时不能简单取 max/min —— 必须确保输入 AABB 本身是合法的(width >= 0, height >= 0)。
- 重叠矩形的
left = std::max(a.left, b.left),right = std::min(a.left + a.width, b.left + b.width),再算width = right - left;但若width <= 0,说明其实没重叠 —— 得先做一次碰撞判定,再算交集,否则会得到负尺寸“伪矩形” - 用
std::max/std::min时注意模板参数类型一致,混用int和float可能触发隐式转换警告甚至精度丢失 - 某些图形 API(如 SDL)的
SDL_IntersectRect返回 bool 并通过指针写入结果,C++ 封装时建议用std::optional<AABB>表达“可能无交集”,比传引用+bool 返回更清晰
重叠计算本身不难,难的是在 pipeline 中保持状态一致性:一旦某个 AABB 因缩放或变换暂时变成退化矩形(width=0),后续交集结果就会失效,这类边界必须在上游卡住。


















