AABB碰撞判定核心是检查各轴投影是否同时重叠:仅当x、y(及z)轴均重叠才判定为碰撞,任一轴分离即无碰撞;采用min/max表示法并用

什么是 AABB 碰撞判定的核心逻辑
两个 AABB(Axis-Aligned Bounding Box)是否重叠,本质是判断它们在 x 轴和 y 轴(2D)或 z 轴(3D)上投影是否**同时重叠**。只要任一轴上不重叠,就无碰撞;只有所有轴都重叠,才算发生冲突。
关键点不是“求交集”,而是“求分离”——先检查是否能轻松排除碰撞,效率更高、逻辑更稳。
用 min/max 坐标实现的最简 2D 判定函数
假设每个 AABB 用左下角 min 和右上角 max 表示(即 min.x ,<code>min.y ),这是最常见且不易出错的表示法:
bool intersect(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;
}注意:全部用 ,不是 <code>。因为当 a.max.x == b.min.x 时,两矩形仅边接触,按常规物理/游戏逻辑视为“未穿透”,不应算碰撞——除非你明确需要包含边界接触。
立即学习“C++免费学习笔记(深入)”;
- 若需包含边接触(如 UI 点击热区),把所有
换成 <code> - 若用中心 + 半宽高(
center,halfExtents)表示,等价转换为:abs(a.center.x - b.center.x) ,但要注意浮点误差累积 - 该函数对坐标系无要求(左手/右手、y 向上/向下),只依赖相对顺序
为什么用 min/max 比用 x, y, width, height 更安全
用 x, y, width, height 表示时,容易因符号或方向误判,尤其当 width 或 height 为负(比如镜像缩放后未归一化):
width 会导致 <code>x + width ,<code>max.x反而变小,后续比较全乱-
min/max天然保证min ,只要构造时做一次校验(<code>std::minmax),后续所有计算可默认成立 - 在 SIMD 或批量检测中,
min/max向量化更直接(如 AVX2 的_mm256_cmp_ps对四组min/max并行比较)
推荐构造函数内强制归一化:
AABB(float x, float y, float w, float h)
: min{std::min(x, x + w), std::min(y, y + h)},
max{std::max(x, x + w), std::max(y, y + h)} {}浮点精度与零尺寸 AABB 的实际坑点
真实项目里,min == max(退化为线或点)很常见(比如刚创建的空区域、动态生成的极小碰撞体)。此时上述判定会返回 true 当且仅当两点完全重合——但多数引擎希望“点碰矩形”也算相交。
- 若需支持退化情况,先加预检:
if (a.min.x == a.max.x || a.min.y == a.max.y || b.min.x == b.max.x || b.min.y == b.max.y) { /* 特殊处理 */ } - 浮点下慎用
==判退化,改用std::abs(a.min.x - a.max.x) - 更鲁棒的做法:统一用带 epsilon 的比较,但注意
EPS不能太大(否则小物体永远“粘”在一起),建议按场景尺度动态设(如1e-5f对单位米尺度足够)
真正难缠的是跨尺度混合:一个 AABB 是公里级地形块,另一个是毫米级粒子——此时固定 EPS 失效,必须做相对误差判断,或提前按比例归一化坐标系。


















