上文中讲到了如何遍历物理世界,但是大家想想,我们访问了世界容器中的每一个物体,只是为了找到一个匹配的对象,这是一个非常耗时的操作,如果游戏当中存在一百个对象,此时开发者只想找到一个发生碰撞的对象,难道就必须要将一百个对象都访问一遍吗?所以Box2D引擎提供了一种访问对象的方式:AABB查询。在Box2D引擎当中,AABB代表了一个固定尺寸的矩形盒子。它是当开发者需要得出一个区域内的所有对象时的解决方法。看代码:
AABB查询例子:
//查询的回调函数
class MyQueryCallback:pubilc b2QueryCallback
{
public:
bool ReportFixture(b2Fixture*fixture)
{
//获得物体链表指针
b2Body* body =fixture->GetBody();
//唤醒物体
body->WakeUp();
//返回true,继续查询
return true;
}
};
MyQueryCallback callback;
//创建一个AABB对象
b2AABB aabb;
//设置AABB的上边界
aabb.lowerBound.Set(-1.0f,-1.0f);
//设置AABB的下边界
aabb.upperBound.Set(1.0f,1.0f);
//开始查询
myWorld->Query(&callback,aabb);
经过上面的代码,我们能够看到AABB查询的使用方法。开发者只需要提供一个物理世界坐标的AABB盒子和b2QueryCallback的一个回调函数的实现。只要物理世界中对象的AABB和需查询的AABB有重合,那么物理世界对象就会回调类b2QueryCallback的函数。
光线投射(Ray Casts)
除了AABB区域之外,Box2D引擎当中还提供了另一种物体的查询方式。那就是开发者可以使用光线投射 去做视线检查或者扫射。通过实现一个回调函数的类,并同时提供一个开始点和结束点,读者就可以执行光线投射。下面例子会获取光线投射中最近的物体:
光线投射查询:
class MyRayCastCallback:public b2RayCastCallback
{
public:
MyRayCastCallback()
{
m_fixture =NULL;
}
//返回值
float32 ReportFixture(b2Fixture,const b2Vec2& point,const b2Vec2& normal,float32 fraction)
{
//保存框架
m_fixture =fixture;
//保存交点
m_point =point;
//保存法向量
m_normal =normal;
//保存光线通过的分数距离
m_fraction =fraction;
return fraction;
}
b2Fixture* m_fixture;
b2Vec2 m_point;
b2Vec2 m_normal;
float32 m_fraction;
};
//回调函数
MyRayCastCallback callback;
//光线投射的起始点
b2Vec2 point(-1.0f,0.0f);
//光线投射的结束点
b2Vec2 point2(3.0f,1.0f);
//开始光线投射
myWorld->RayCast(&callback,point1,point2);
上述代码中回调函数类MyRayCastCallback是光线投射运算后执行的函数。只要有框架fixture被光线投射穿过时,物理世界就会调用回调函数类中的函数ReportFixture。另外fraction的数值也有一定的意义,用来控制光线投射是否继续进行。为0代表结束光线投射,为1代表继续投射,并且没有和其他形状相交。为-1表示过滤当前发现的框架fixture,光线会继续进行。