程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> Box2D碰撞過濾規則

Box2D碰撞過濾規則

編輯:C++入門知識

首先注意這個函數:
[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}}

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved