AABB矩形指的是轴对齐包围盒矩形,即矩形的四条边分别和坐标轴平行,是游戏碰撞检测、图形交互场景中最常用的矩形碰撞判定模型。这种矩形的碰撞判断不需要复杂的旋转计算,仅通过坐标范围的比较就能完成判定,效率非常高。

AABB矩形碰撞的核心原理
AABB矩形的位置通常用两个点的坐标来表示,一般是左上角坐标(x1, y1)和右下角坐标(x2, y2),或者最小坐标(min_x, min_y)和最大坐标(max_x, max_y)。两个AABB矩形发生碰撞的本质是:两个矩形在X轴和Y轴上的投影范围都存在重叠。
我们可以把问题拆解为两个独立的维度判断:
- X轴方向:矩形A的X坐标范围和矩形B的X坐标范围有重叠
- Y轴方向:矩形A的Y坐标范围和矩形B的Y坐标范围有重叠
只有两个维度同时满足重叠条件,两个矩形才会发生碰撞。
X轴重叠的判定逻辑
假设矩形A的X范围是[ax_min, ax_max],矩形B的X范围是[bx_min, bx_max],那么X轴重叠的条件是:ax_min < bx_max 且 bx_min < ax_max。如果这个条件不满足,说明两个矩形在X轴上完全没有交集,不可能发生碰撞。
Y轴重叠的判定逻辑
同理,矩形A的Y范围是[ay_min, ay_max],矩形B的Y范围是[by_min, by_max],Y轴重叠的条件是:ay_min < by_max 且 by_min < ay_max。
C++实现AABB矩形碰撞检测
首先我们定义一个矩形结构体,用来存储AABB矩形的坐标信息:
// 定义AABB矩形结构体
struct AABBRect {
float min_x; // 最小X坐标
float min_y; // 最小Y坐标
float max_x; // 最大X坐标
float max_y; // 最大Y坐标
// 构造函数,支持传入左上角和右下角坐标初始化
AABBRect(float x1, float y1, float x2, float y2) {
min_x = x1 < x2 ? x1 : x2;
min_y = y1 < y2 ? y1 : y2;
max_x = x1 > x2 ? x1 : x2;
max_y = y1 > y2 ? y1 : y2;
}
};
接下来实现碰撞检测函数,将两个矩形作为参数传入,返回布尔值表示是否碰撞:
// 判断两个AABB矩形是否碰撞
bool isAABBCollide(const AABBRect& rectA, const AABBRect& rectB) {
// 判断X轴是否重叠
bool xOverlap = rectA.min_x < rectB.max_x && rectB.min_x < rectA.max_x;
// 判断Y轴是否重叠
bool yOverlap = rectA.min_y < rectB.max_y && rectB.min_y < rectA.max_y;
// 两个轴都重叠才发生碰撞
return xOverlap && yOverlap;
}
测试代码验证
我们编写测试代码验证不同场景下的碰撞判定结果:
#include <iostream>
using namespace std;
// 这里粘贴上面的AABBRect结构体和isAABBCollide函数
int main() {
// 场景1:两个矩形完全重叠
AABBRect rect1(0, 0, 100, 100);
AABBRect rect2(20, 20, 80, 80);
cout << "场景1 完全重叠: " << (isAABBCollide(rect1, rect2) ? "碰撞" : "不碰撞") << endl;
// 场景2:两个矩形边缘相切
AABBRect rect3(0, 0, 100, 100);
AABBRect rect4(100, 0, 200, 100);
cout << "场景2 边缘相切: " << (isAABBCollide(rect3, rect4) ? "碰撞" : "不碰撞") << endl;
// 场景3:两个矩形完全分离
AABBRect rect5(0, 0, 100, 100);
AABBRect rect6(150, 150, 250, 250);
cout << "场景3 完全分离: " << (isAABBCollide(rect5, rect6) ? "碰撞" : "不碰撞") << endl;
// 场景4:两个矩形部分重叠
AABBRect rect7(0, 0, 100, 100);
AABBRect rect8(50, 50, 150, 150);
cout << "场景4 部分重叠: " << (isAABBCollide(rect7, rect8) ? "碰撞" : "不碰撞") << endl;
return 0;
}
运行上述代码,输出结果为:
- 场景1 完全重叠: 碰撞
- 场景2 边缘相切: 不碰撞
- 场景3 完全分离: 不碰撞
- 场景4 部分重叠: 碰撞
这里需要注意,我们的判定逻辑中,边缘相切的情况返回不碰撞,如果需要把相切也算作碰撞,只需要把比较符号<改成<=即可,根据实际业务需求调整。
常见错误和注意事项
很多开发者在写判定逻辑时会写成ax_max > bx_min && ax_min < bx_max,这和我们上面的逻辑是等价的,没有问题。但容易出现的错误是只判断一个维度的重叠,或者把逻辑写成ax_max > bx_min && ax_min < bx_max && ay_max > by_min && ay_min < by_max时,不小心把逻辑运算符写错,导致判定结果异常。
另外,如果矩形坐标是用左上角和宽高表示的,比如(x, y, width, height),需要先转换为min_x, min_y, max_x, max_y的形式再进行计算,转换公式为:min_x = x; min_y = y; max_x = x + width; max_y = y + height,注意width和height需要是正数,如果可能出现负数宽高,需要先取绝对值再计算。