跳转到主内容
websoft网络软件专家 - 深耕网络技术,打造实用软件!

C++ 判断两个 AABB 轴对齐矩形是否发生重叠碰撞 _ 坐标判定逻辑【干货】

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

相关文章