导读:本期聚焦于张衡创作的《C++如何判断两个AABB轴对齐矩形是否发生碰撞?坐标判定方法详解》,敬请观看详情。AABB碰撞检测是游戏开发和物理引擎中最基础也最常用的技术之一。所谓AABB,指的是轴对齐包围盒,即矩形的边始终与坐标轴平行,这种特性让碰撞判断只需要简单的坐标比较就能完成。本文将围绕C++实现AABB碰撞检测展开,先讲清矩形相交的数学原理,再给出基础版本的判定代码和优化版本的性能写法,同时分析浮点数精度、中心点表示法与左上角表示法的差异,以及常见踩坑点。无论你是在做2D游戏还是为3D场景做粗筛检测,掌握这套坐标判定思路都能直接落地使用。

AABB是Axis-Aligned Bounding Box的缩写,中文叫轴对齐包围盒。简单说,就是一个矩形的四条边永远和坐标系的X轴、Y轴保持平行,不会旋转。正因为有这个约束,判断两个AABB是否重叠根本不需要复杂的几何运算,只做几次坐标大小的比较就够了。这篇文章会把原理、代码和优化技巧一次讲透。

C++如何判断两个AABB轴对齐矩形是否发生碰撞?坐标判定方法详解

一、AABB碰撞判定的核心原理

先从直觉上理解:两个矩形什么时候算“碰撞”?当它们在投影到X轴上的区间有重叠,并且投影到Y轴上的区间也有重叠时,矩形本身才重叠。只要有一个轴上的投影完全分开,两个矩形就一定不相交。这就是著名的分离轴定理在轴对齐情况下的特例。

假设矩形A的横坐标范围是[xMinA, xMaxA],矩形B的横坐标范围是[xMinB, xMaxB]。那么X轴方向重叠的条件是:A的右边界大于B的左边界,同时A的左边界小于B的右边界。用公式表达就是xMaxA >= xMinB && xMinA <= xMaxB。Y轴方向同理。两个方向同时满足,碰撞发生。

这里有个容易踩的坑:到底用>还是>=?如果两个矩形恰好边缘贴边缘,比如A的右边界正好等于B的左边界,这算不算碰撞?在大多数游戏场景里,贴边不算碰撞,用严格大于号;但在某些物理引擎中,恰好接触也算碰撞,用等号。写代码前要想清楚你的业务需求,这个细节会直接影响手感的判断。

二、基础实现:基于最小最大坐标的结构体

最常见的做法是用两个点表示矩形:左上角加右下角(屏幕坐标系Y向下),或者最小点加最大点(数学坐标系Y向上)。下面给出一个完整的C++实现,结构清晰,适合直接嵌入项目。

#include <iostream>
#include <algorithm>

struct AABB {
    float minX, minY;  // 左边界、下边界
    float maxX, maxY;  // 右边界、上边界
};

// 判断两个AABB是否相交(贴边不算碰撞)
bool isColliding(const AABB& a, const AABB& b) {
    if (a.maxX <= b.minX) return false; // A在B的左侧
    if (a.minX >= b.maxX) return false; // A在B的右侧
    if (a.maxY <= b.minY) return false; // A在B的下方
    if (a.minY >= b.maxY) return false; // A在B的上方
    return true; // 四个方向都不满足分离条件,说明重叠
}

int main() {
    AABB box1{0.0f, 0.0f, 10.0f, 10.0f};
    AABB box2{5.0f, 5.0f, 15.0f, 15.0f};

    if (isColliding(box1, box2)) {
        std::cout << "发生碰撞" << std::endl;
    } else {
        std::cout << "未碰撞" << std::endl;
    }
    return 0;
}

这种写法逻辑上很好理解:只要矩形B完全位于A的某一侧外部,二者就分离。四个条件依次排除上下左右四种分离情况,剩下的自然就是重叠。它的优点是判断顺序直观,缺点是浮点比较没有处理精度问题,后面会专门讲。

还有一种等价的“短路”写法,把四个条件合并成一个返回语句,代码更紧凑:return !(a.maxX <= b.minX || a.minX >= b.maxX || a.maxY <= b.minY || a.minY >= b.maxY);。编译器优化后两种写法的机器码几乎一样,选哪种主要看团队代码风格。

三、中心点表示法与判定的另一种思路

游戏引擎里经常用“中心点加半宽高”的方式存储AABB,比如角色的位置就是包围盒中心。这种表示法下判定公式要换一种推导:两个矩形在X轴上重叠,等价于两个中心点的X距离小于两个半宽之和。用数学式表达就是|cxA - cxB| < halfWA + halfWB,Y轴同理。

struct AABBCenter {
    float cx, cy;   // 中心点坐标
    float hw, hh;   // 半宽、半高
};

bool isCollidingCenter(const AABBCenter& a, const AABBCenter& b) {
    float dx = std::abs(a.cx - b.cx);
    float dy = std::abs(a.cy - b.cy);
    return dx < (a.hw + b.hw) && dy < (a.hh + b.hh);
}

这种写法的好处是求距离时可以用平方比较避开开方,不过对于AABB本身来说没有开方运算,优势不明显。它真正的价值在于和圆形碰撞检测、球形检测的公式形式统一,方便封装成模板或泛型接口。另外,中心点表示法在物体移动时更新包围盒更方便,只需要改中心坐标,不用重新计算两个角点。

两种表示法可以互相转换:已知min和max,中心点就是二者之和除以二,半宽就是差值除以二。反过来也成立。工程上建议根据数据来源选择:如果碰撞数据来自地图编辑器导出的矩形区域,用min-max更自然;如果来自移动物体,用中心点表示更顺手。

四、性能优化与工程实践细节

单次AABB判断快到可以忽略不计,但真实场景中往往是几百上千个物体两两检测,复杂度是O(n²)。这时除了用空间划分(网格、四叉树)减少检测对数量,还可以在单次判断层面抠细节。比如把参数标记为const引用避免拷贝,用[[nodiscard]]提示调用者不要忽略返回值,以及在循环密集的场景下开启编译器优化。

浮点精度是另一个实际问题。如果坐标经过多帧累加运算,两个“理论上相等”的边界可能差出一个极小值,导致判定结果抖动。解决办法是引入一个小的容差值epsilon,把比较写成a.maxX >= b.minX - epsilon的形式。epsilon的取值要看场景尺度,一般取坐标量级的百万分之一即可,不要无脑用一个固定值。

最后提醒一点:AABB只适合不旋转的物体。如果物体带旋转角度,轴对齐包围盒会随着旋转变得松散,产生大量“假碰撞”。这种情况下要么把旋转物体近似成多个小AABB拼接,要么直接换成OBB(有向包围盒)检测。另外在3D场景中,AABB判定只需扩展一个Z轴维度,把四条件变六条件即可,公式完全同理,这也是它被广泛用作物理引擎粗筛阶段的原因。

五、总结

AABB碰撞检测的本质就一句话:两个轴上的投影区间同时重叠,矩形就重叠。实现上从分离条件的反面入手,排除所有分离情况,剩下的就是碰撞。掌握min-max表示和中心点表示两种写法,注意贴边语义和浮点容差这两个细节,再配合空间划分降低检测规模,就足以应对绝大多数2D游戏和3D粗筛场景。理解了这套坐标判定思路,后面学习圆形碰撞、OBB乃至完整的物理引擎都会轻松很多。

C++碰撞检测AABB轴对齐矩形修改时间:2026-09-06 12:12:38

免责声明:已尽一切努力确保本网站所含信息的准确性。网站作品多为原创整理与精心创作,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们进行处理Email:chomcom@qq.com。
引用或转载本作品时,请注明当前出处:https://www.ipipp.com/html/20260906/51539.html,基于非商业用途的前提下,欢迎转载或二创本作品。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。