Box2D碰撞过滤规则
首先注意这个函数:
[cpp]
virtual bool ShouldCollide(b2Fixture* fixtureA, b2Fixture* fixtureB);
函数实现位于 b2WorldCallbacks.cpp line:24
[cpp]
bool b2ContactFilter::ShouldCollide(b2Fixture* fixtureA, b2Fixture* fixtureB)
{
const b2Filter& filterA = fixtureA->GetFilterData();
const b2Filter& filterB = fixtureB->GetFilterData();
if (filterA.groupIndex == filterB.groupIndex && filterA.groupIndex != 0)
{
return filterA.groupIndex > 0;
}
bool collide = (filterA.maskBits & filterB.categoryBits) != 0 && (filterA.categoryBits & filterB.maskBits) != 0;
return collide;
}
这是默认的碰撞过滤回调函数。
由函数实现可以看出, 当 filterA.groupIndex == filterB.groupIndex 时, 若二者 groupIndex >0, 两个fixture一定碰撞; 若 groupIndex<0,二者一定不碰撞。
如果两个 fixture 的 groupIndex 不相等, 那么再判断 二者中是否有一方的 maskBits 包含了另一方的 categoryBits, 即代码里的“&运算”不为零——如果是,返回 true; 否则返回 false。
由此可以看出:
1. 默认的碰撞标记优先级为: groupIndex 高于 maskBits+categoryBits
2. (filterA.maskBits & filterB.categoryBits) != 0 && (filterA.categoryBits & filterB.maskBits) != 0 表示A, B 的 maskBits, categoryBits,必须互相包含包含对方, 函数才返回 true。 举例说明: 如果 filterA.categoryBits=1, filterB.categoryBits=2, filterA.maskBits=3, filterB.maskBits=2, 那么虽然 (3&2)!=0, 但是 (2&1)==0, 所以AB不会碰撞。假设这里的A、B分别代表“一种”而不是“一个”fixture的话,那么可以判定 A种种内相互碰撞, B种种内也相互碰撞。
===================================================
那么, 怎么使用自定义 ShouldCollide 函数呢?
简单的演示一下。
1. 自定义 b2ContactFilter 的一个子类:
[cpp]
class MyContactFilter : public b2ContactFilter{
public:
virtual bool ShouldCollide(b2Fixture* fixtureA, b2Fixture* fixtureB){
return true; //不管谁谁,大家都碰撞
}
};
2. 在你 new b2World(gravity) 的地方,紧接着添加:
[cpp]
MyContactFilter* cf=new MyContactFilter;
_world->SetContactFilter(cf);
这样一来,不管你怎么设定 fixture 的 groupIndex, maskBits, categoryBits 所有的 body 都会碰撞。
【注意】 在 box2d 里面, b2World, b2ContactFilter, b2ContactListener 是少有的几个不被引擎管理, 而需要自己 new 的类, 一定要记得在析构函数中 delete 他们。 如果 自定义的 contactFilter 不是成员变量,可以在析构函数里这么释放:
[cpp]
delete _world->GetContactManager().m_contactFilter;
======================================================
再来看看一个引擎里的例子: TestCpp - Box2DTestBed 里的 CollisionFiltering.h (函数实现都在这个头文件里了)
我们只看文件开始定义的这几个常量:
[cpp]
const int16 k_smallGroup = 1;
const int16 k_largeGroup = -1;
const uint16 k_defaultCategory = 0x0001;
const uint16 k_易做图Category = 0x0002;
const uint16 k_boxCategory = 0x0004;
const uint16 k_circleCategory = 0x0008;
const uint16 k_易做图Mask = 0xFFFF;
const uint16 k_boxMask = 0xFFFF ^ k_易做图Category;
const uint16 k_circleMask = 0xFFFF;
假设我们没有去覆写 ShouldCollide, 就用的引擎默认的函数。可以看出,smallGroup (对应场景里的小物体 ) 必然碰撞,因为 k_smallGroup = 1 大于 0; k_largeGroup (大物体) 互相一定不碰撞, 因为 -1<0 。
而对于大小物体之间,因为
k_易做图Mask = 0xFFFF;
k_boxMask = 0xFFFF ^ k_易做图Category; // 这样 boxMask 就不“包含” 易做图Category 了
k_circleMask = 0xFFFF;
所以小三角和大方块不碰撞,大三角和小方块也不碰撞, 其他的大物体和小物体都会碰撞
{{OVER}}
补充:软件开发 , C++ ,