Box2Dの衝突フィルタについてちょっとソース追ってみた

※ソースは激しく端折ってます。

衝突フィルタはシェイプが重なったときに衝突の処理を動かすかどうかを決めるために使用される。

public class b2ContactManager extends b2PairCallback
{
  public override function PairAdded(proxyUserData1:*, proxyUserData2:*):*{
    if (m_world.m_filter != null && !m_world.m_filter.ShouldCollide(shape1, shape2))
    {
      return m_nullContact;
    }
  }
}

ということなので物体が重なってもm_world.m_filterが設定されていて、そのShouldCollideメソッドがfalseを返した場合、衝突はなかったことにされる。

public class b2World
{
  public function b2World(worldAABB:b2AABB, gravity:b2Vec2, doSleep:Boolean){
    m_filter = b2CollisionFilter.b2_defaultFilter;
  }
  public var m_filter:b2CollisionFilter;
}

ということで、m_filterはb2CollisionFilterインスタンスで、そのデフォルト値はb2CollisionFilter.b2_defaultFilterに設定されている。

public class b2CollisionFilter
{
  public virtual function ShouldCollide(shape1:b2Shape, shape2:b2Shape):Boolean{
    if (shape1.m_groupIndex == shape2.m_groupIndex && shape1.m_groupIndex != 0)
    {
      return shape1.m_groupIndex > 0;
    }
		
    var collide:Boolean = (shape1.m_maskBits & shape2.m_categoryBits) != 0 && 
      (shape1.m_categoryBits & shape2.m_maskBits) != 0;
    return collide;
  }
	
  static public var b2_defaultFilter:b2CollisionFilter = new b2CollisionFilter;
};

b2CollisionFilterのソースはこれで全部。つまりデフォルトのフィルタの実装は次のようになる。

  • シェイプ同士のm_groupIndexがゼロ以外で等しければ、その衝突はm_groupIndexの符号に従う
    • 正なら衝突が発生
    • 負なら衝突は発生しない
  • シェイプのm_groupIndexのいずれかがゼロであるか、それぞれ異なる値を持つ場合は
    • 一方のマスクビットと他方のカテゴリビットのANDが共にゼロでない場合に衝突が発生する

はずなのに・・・