首先注意這個函數:
[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_triangleCategory = 0x0002;
const uint16 k_boxCategory = 0x0004;
const uint16 k_circleCategory = 0x0008;
const uint16 k_triangleMask = 0xFFFF;
const uint16 k_boxMask = 0xFFFF ^ k_triangleCategory;
const uint16 k_circleMask = 0xFFFF;
假設我們沒有去覆寫 ShouldCollide, 就用的引擎默認的函數。可以看出,smallGroup (對應場景裡的小物體 ) 必然碰撞,因為 k_smallGroup = 1 大於 0; k_largeGroup (大物體) 互相一定不碰撞, 因為 -1<0 。
而對於大小物體之間,因為
k_triangleMask = 0xFFFF;
k_boxMask = 0xFFFF ^ k_triangleCategory; // 這樣 boxMask 就不“包含” triangleCategory 了
k_circleMask = 0xFFFF;
所以小三角和大方塊不碰撞,大三角和小方塊也不碰撞, 其他的大物體和小物體都會碰撞
{{OVER}}