AABB碰撞判定的核心逻辑是:两个AABB在x轴和y轴(2D)或x/y/z轴(3D)上投影必须同时重叠才相交;任一轴分离即无碰撞,本质是应用分离轴定理的最简形式,通过比较min/max边界高效判断。

什么是 AABB 碰撞判定的核心逻辑
两个 AABB(Axis-Aligned Bounding Box)是否相交,本质是判断它们在 x 轴和 y 轴(2D)或 z 轴(3D)上投影是否**同时重叠**。只要任一轴上不重叠,就无碰撞;只有所有轴都重叠,才算真正相交。
关键不是“计算交集”,而是用“分离轴定理”的最简形式:对每个坐标轴,检查一个矩形的最小值是否大于另一个的最大值(即完全在右侧/上方/前方),只要有一个成立,就分离。
C++ 中用结构体表示 AABB 并实现判别函数
推荐用 struct 显式定义边界,避免依赖顺序或隐式构造。常见错误是把 min/max 搞反,或误用中心+半宽方式但未做归一化。
struct AABB {
float min_x, min_y, max_x, max_y;
// 注意:必须保证 min_x <= max_x 且 min_y <= max_y,否则判定失效
};
<p>bool intersects(const AABB& a, const AABB& b) {
if (a.max_x < b.min_x || b.max_x < a.min_x) return false;
if (a.max_y < b.min_y || b.max_y < a.min_y) return false;
return true;
}
- 参数用
const AABB&避免拷贝,尤其当结构体含更多字段时 - 比较顺序不重要,但建议先
x后y,便于早期退出(多数场景下 x 方向更易分离) - 若使用
std::numeric_limits<float>::quiet_NaN()</float>初始化边界,会导致比较结果未定义——务必确保所有字段为有效浮点数
坐标系方向与浮点精度带来的坑
Y 轴朝上(OpenGL/WebGL)还是朝下(DirectX/屏幕坐标)不影响判定逻辑,因为只比大小;但若混用不同坐标系的 AABB 数据(比如一个来自 UI 坐标、一个来自物理引擎),min_y/max_y 可能被误翻转,导致永远返回 false。
立即学习“C++免费学习笔记(深入)”;
浮点误差在边界几乎相接时会暴露:例如 a.max_x == b.min_x 理论上应算“接触”,但因计算误差变成 a.max_x ,被误判为分离。实际工程中常加 epsilon 容差:
const float EPS = 1e-5f; if (a.max_x + EPS < b.min_x || b.max_x + EPS < a.min_x) return false;
- 容差不能过大,否则小物体穿模变明显
- 若用
double,EPS 应相应调小(如1e-12) - 游戏物理中更倾向用“穿透深度”而非布尔判定,此时需额外计算重叠量,不能只靠
intersects
扩展到 3D 或与其他形状混合时要注意什么
3D 只需增加 min_z/max_z 和第三组比较,逻辑完全一致。但要注意:很多所谓“AABB”实际是 OBB(方向矩形),直接套用此算法会严重漏判。
若要和圆形(Circle)做混合判定,不能复用该函数——AABB vs Circle 需找矩形上离圆心最近的点,再算距离,和轴投影无关。
另外,某些图形 API(如 SDL2 的 SDL_HasIntersection())内部就是此算法,但参数是 SDL_Rect(整数坐标)。传入浮点计算后的 AABB 时,若做了截断(trunc)而非四舍五入,可能让本应接触的框错失判定。
最易被忽略的是:AABB 本身是否随物体旋转而更新。一旦物体旋转,其轴对齐包围盒必须重新计算(取顶点变换后的极值),否则 intersects() 仍在用旧的、过大的框做判断,导致“假阳性”碰撞。


















