cocos2d-x-3.3-021-碰撞检测3-物理引擎碰撞过滤

时间:2023-02-08 08:10:05

原文同步发布于我的wiki,查看原文或更新请移步: 点击打开链接


引子

  • 上一篇简单演示了如何使用物理引擎以及用它来作碰撞监测。但有问题,那就是敌人和敌人也会发生碰撞,子弹和子弹之间也会发生碰撞。。。要解决这个问题(避免不必要的碰撞,或碰撞过滤),得先看看cocos封装物理引擎后给我们提供的API。

PhysicsBody相关API说明

  • void setGroup(int group);
      Collision groups let you specify an integral group index. 
You can have all fixtures with the same group index always collide
(positive index) or never collide (negative index)
it have high priority than bit masks


PhysicsBody的Group
1.优先级比bit masks的优先级高(CategoryBitmask,ContactTestBitmask,CollisionBitmask)
2.group是正数且相等的话,就一定碰撞
3.group是负数且相等的话,就一定不会碰撞
4.group其他情况没说,应该是取决于bit masks了
  • void setCategoryBitmask(int bitmask);
      A mask that defines which categories this physics body belongs to.
Every physics body in a scene can be assigned to up to 32
different categories, each corresponding to a bit in the bit mask.
You define the mask values used in your game.
In conjunction with the collisionBitMask and contactTestBitMask properties,
you define which physics bodies interact with each other
and when your game is notified of these interactions.
The default value is 0xFFFFFFFF (all bits set).


PhysicsBody的CategoryBitmask
1.CategoryBitmask用来标记这个PhysicsBody的所属类别
2.每个PhysicsBody最多可以属于32个类别,一个bit代表一个类别,0代表不是对应类别,1代表是对应类别
3.和另外两个属性(collisionBitMask and contactTestBitMask)配合着用
4.默认值0xFFFFFFFF,即这个PhysicsBody分别属于所有的32个类别
  • void setContactTestBitmask(int bitmask);
      A mask that defines which categories of bodies cause intersection 
notifications with this physics body.
When two bodies share the same space, each body’s category mask is
tested against the other body’s contact mask by performing a logical
AND operation. If either comparison results in a non-zero value,
an PhysicsContact object is created and passed to the physics
world’s delegate. For best performance, only set bits in the
contacts mask for interactions you are interested in.
The default value is 0x00000000 (all bits cleared).


PhysicsBody的ContactTestBitmask
1.ContactTestBitmask用来定义哪个类别的PhysicsBody可以和这个PhysicsBody产生相交通知
2.举个例子:有PhysicsBody A B占了同样的空间了。如何判断A B要产生相交通知呢,
if((A.CategoryBitmask & B.ContactTestBitmask) != 0 || (A.ContactTestBitmask & B.CategoryBitmask) != 0)
{/*条件成立,执行相交通知*/}
else{/*没有相交通知*/}
3.为了性能考虑,相交通知只应该设置给我们感兴趣的物体
4.默认值0x00000000 (all bits cleared),没有哪个类别的PhysicsBody可以产生相交通知
  • void setCollisionBitmask(int bitmask);
      A mask that defines which categories of physics bodies 
can collide with this physics body.
When two physics bodies contact each other, a collision may occur.
This body’s collision mask is compared to the other body’s category
mask by performing a logical AND operation. If the result is a
non-zero value, then this body is affected by the collision.
Each body independently chooses whether it wants to be affected
by the other body. For example, you might use this to avoid collision
calculations that would make negligible changes to a body’s velocity.
The default value is 0xFFFFFFFF (all bits set).


PhysicsBody的CollisionBitmask
1.CollisionBitmask是用来定义哪个类别的PhysicsBody可以和这个PhysicsBody产生碰撞
2.举个例子:有PhysicsBody A B彼此接触了,那碰撞就可能发生。
A受不受这个碰撞的影响(体现为物理效果)表达为:
if((A.CollisionBitmask & B.CategoryBitmask) != 0 ){/*A产生碰撞的物理效果*/}
else{/*A没效果*/}
3.至于B受不受这个碰撞的影响,则采用同样的表达式单独计算即可
if((B.CollisionBitmask & A.CategoryBitmask) != 0 ){/*B产生碰撞的物理效果*/}
else{/*B没效果*/}
4.默认值0xFFFFFFFF (all bits set),所有类别的PhysicsBody都能对this body产生碰撞效果

DEMO及源码

  • 基于cocos 3.4final
  • DEMO功能:注册了物理碰撞事件的监听,用来查看是否有事件回调;注册了touch事件监听,在touch的结束事件里回在触摸点创建一个带物理效果的精灵。精灵有两种,用来测试PhysicsBody的设置造成的影响。具体看代码,不复杂。
  • https://github.com/cheyiliu/CollisionDetection

验证对API的理解

所有参数保持默认

属性值:
group =0
CategoryBitmask =0xFFFFFFFF
ContactTestBitmask=0x00000000
CollisionBitmask =0xFFFFFFFF

  • 现象和分析:
    1. a b为同一类物品,有碰撞现象【group未设置; 那就套上面的API的分析,(a.CategoryBitmask
      & b.CollisionBitmask) != 0
       true; 反过来也是; 故a b都有碰撞效果。】
    2. a b为同一类物品,无碰撞回调【套公式 ((a.CategoryBitmask & b.ContactTestBitmask) != 0 || (a.ContactTestBitmask & b.CategoryBitmask) != 0)等于false,故没回调。】

确认group优先级

属性值:
group =需要设置<-----
CategoryBitmask =0xFFFFFFFF
ContactTestBitmask=0x00000000
CollisionBitmask =0xFFFFFFFF

  • 现象和分析:
    1. a b为同一类物品,group都取1。有碰撞现象,无回调【跟group不设置时现象一样,还不能说明什么】
    2. a b为同一类物品,group都取-1。无碰撞现象,无回调,物体a b分别从同一个位置落下后,a b重叠【其他bitmask的默认值设置是有碰撞现象的,但设置group取相同的负数后没碰撞了,group优先级高!】
    3. a b为同一类物品,group都取1,但设置CollisionBitmask=0x00(试图不要碰撞效果)。现象1*落体到世界外面去了,现象2快速touch在同一个位置产生两个精灵会有挤开的现象(若group取-1则不会挤开,叠在一起了)。【说明group的优先级最高!】
    4. a b为同一类物品,group都取1,但设置CollisionBitmask=0x00(试图不要碰撞效果),设置ContactTestBitmask=0x01(试图获取回调)。现象1*落体到世界外面去了;现象2快速touch在同一个位置产生两个精灵会有挤开的现象(若group取-1则不会挤开,叠在一起了);现象3有回调。【说明group的优先级最高!】

想要回调

属性值:
group =0
CategoryBitmask =0xFFFFFFFF
ContactTestBitmask=0x00000001<-----change to this
CollisionBitmask =0xFFFFFFFF

  • 现象和分析:
    1. a b为同一类物品,有碰撞现象,有回调【碰撞的理由是(a.CollisionBitmask
      & b.CategoryBitmask) != 0
      非0, true;有回调的理由是((a.CategoryBitmask & b.ContactTestBitmask) != 0 || (a.ContactTestBitmask & b.CategoryBitmask) != 0) 等于true】

想要回调但不要碰撞效果

属性值:
group =0
CategoryBitmask =0xFFFFFFFF
ContactTestBitmask=0x00000001<-----change to this
CollisionBitmask =0x00000000<-----change to this

  • 现象和分析:
    1. a b为同一类物品,无碰撞现象,无回调【不碰撞的理由是(a.CollisionBitmask
      & b.CategoryBitmask) != 0
       等于0,false,;无回调的理由是虽然((a.CategoryBitmask & b.ContactTestBitmask) != 0|| (a.ContactTestBitmask & b.CategoryBitmask) != 0) 等于true,但是没有碰撞的前提】

想要A类和B类碰撞,A类之间不碰撞,B类之间不碰撞-法1

属性值:
group =0【A的group取-1;B的group取-2】
CategoryBitmask =0xFFFFFFFF
ContactTestBitmask=0xFFFFFFFF【AB都取这个值】
CollisionBitmask =0xFFFFFFFF

  • 现象和分析:
    1. 同类之间不碰撞,a b为同一类物品【group决定的,相同的负的group值的对象不会碰撞;虽然((a.CategoryBitmask
      & b.ContactTestBitmask) != 0 || (a.ContactTestBitmask & b.CategoryBitmask) != 0)
      等于true,但没碰撞的前提,故无回调】
    2. 不同类可以碰撞,a b为不同类的物品【group的值不一样,取决于bitmask了;碰撞的理由是(a.CollisionBitmask & b.CategoryBitmask) != 0非0,true,b也是;回调理由是有碰撞且((a.CategoryBitmask & b.ContactTestBitmask) != 0 || (a.ContactTestBitmask & b.CategoryBitmask) != 0) 等于true】

想要A类和B类碰撞,A类之间不碰撞,B类之间不碰撞-法2

属性值:
group =0【AB都保持默认0】
CategoryBitmask =【A的CategoryBitmask=0x01;B的CategoryBitmask=0x02】
ContactTestBitmask=【A的ContactTestBitmask=0x02;B的ContactTestBitmask=0x01】
CollisionBitmask =【A的CollisionBitmask=0x02;B的CollisionBitmask=0x01】

  • 现象和分析:
    1. 同类之间无碰撞,a b为同一类物品【无碰撞的理由是(a.CollisionBitmask
      & b.CategoryBitmask) != 0
      false; 无回调是((a.CategoryBitmask & b.CollisionBitmask) != 0 || (a.CollisionBitmask & b.CategoryBitmask) != 0)等于false故无回调】
    2. 不同类可以碰撞,a b为不同类的物品【碰撞的理由是(a.CollisionBitmask & b.CategoryBitmask) != 0true,b也是;回调理由是有碰撞且((a.CategoryBitmask & b.ContactTestBitmask) != 0 || (a.ContactTestBitmask & b.CategoryBitmask) != 0)等于true】

效果图

  • 想要A类和B类碰撞,A类之间不碰撞,B类之间不碰撞(NOTE: gif中,相同的图片是同一类,不同图片类型不同) 
  • https://github.com/cheyiliu/All-in-One/raw/master/res/cocos2d/CollisionDetection-way3-use-physics-engine-filter.gif

总结

  • 能碰撞,不能碰撞以及碰撞事件通知的大致逻辑
PhysicsBody a;
PhysicsBody b;

if ((a.group == b.group) && a.group > 0) {
/*能碰撞,有碰撞的物理效果*/
if (((a.CategoryBitmask & b.ContactTestBitmask) != 0)
|| ((a.ContactTestBitmask & b.CategoryBitmask) != 0)) {
/*条件成立,执行相交通知*/
}
} else if ((a.group == b.group) && a.group < 0) {
/*不能碰撞,没有碰撞的物理效果*/
} else {
if ((a.CollisionBitmask & b.CategoryBitmask) != 0) {
/*a能碰撞,a有碰撞的物理效果*/
if (((a.CategoryBitmask & b.ContactTestBitmask) != 0)
|| ((a.ContactTestBitmask & b.CategoryBitmask) != 0)) {
/*条件成立,执行相交通知*/
}
} else {
/*a不能碰撞,a没有碰撞的物理效果*/
}

if ((b.CollisionBitmask & a.CategoryBitmask) != 0) {
/*b能碰撞,b有碰撞的物理效果*/
if (((a.CategoryBitmask & b.ContactTestBitmask) != 0)
|| ((a.ContactTestBitmask & b.CategoryBitmask) != 0)) {
/*条件成立,执行相交通知*/
}
} else {
/*b不能碰撞,b没有碰撞的物理效果*/
}

}