原文同步发布于我的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
- 现象和分析:
- a b为同一类物品,有碰撞现象【group未设置; 那就套上面的API的分析,
(a.CategoryBitmask & b.CollisionBitmask) != 0
true; 反过来也是; 故a b都有碰撞效果。】 - a b为同一类物品,无碰撞回调【套公式
((a.CategoryBitmask & b.ContactTestBitmask) != 0 || (a.ContactTestBitmask & b.CategoryBitmask) != 0)
等于false,故没回调。】
- a b为同一类物品,有碰撞现象【group未设置; 那就套上面的API的分析,
确认group优先级
- 属性值:
- group =需要设置<-----
- CategoryBitmask =0xFFFFFFFF
- ContactTestBitmask=0x00000000
- CollisionBitmask =0xFFFFFFFF
- 现象和分析:
- a b为同一类物品,group都取1。有碰撞现象,无回调【跟group不设置时现象一样,还不能说明什么】
- a b为同一类物品,group都取-1。无碰撞现象,无回调,物体a b分别从同一个位置落下后,a b重叠【其他bitmask的默认值设置是有碰撞现象的,但设置group取相同的负数后没碰撞了,group优先级高!】
- a b为同一类物品,group都取1,但设置CollisionBitmask=0x00(试图不要碰撞效果)。现象1自由落体到世界外面去了,现象2快速touch在同一个位置产生两个精灵会有挤开的现象(若group取-1则不会挤开,叠在一起了)。【说明group的优先级最高!】
- 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
- 现象和分析:
- a b为同一类物品,有碰撞现象,有回调【碰撞的理由是
(a.CollisionBitmask & b.CategoryBitmask) != 0
非0,true;有回调的理由是((a.CategoryBitmask & b.ContactTestBitmask) != 0 || (a.ContactTestBitmask & b.CategoryBitmask) != 0)
等于true】
- a b为同一类物品,有碰撞现象,有回调【碰撞的理由是
想要回调但不要碰撞效果
- 属性值:
- group =0
- CategoryBitmask =0xFFFFFFFF
- ContactTestBitmask=0x00000001<-----change to this
- CollisionBitmask =0x00000000<-----change to this
- 现象和分析:
- a b为同一类物品,无碰撞现象,无回调【不碰撞的理由是
(a.CollisionBitmask & b.CategoryBitmask) != 0
等于0,false,;无回调的理由是虽然((a.CategoryBitmask & b.ContactTestBitmask) != 0|| (a.ContactTestBitmask & b.CategoryBitmask) != 0)
等于true,但是没有碰撞的前提】
- a b为同一类物品,无碰撞现象,无回调【不碰撞的理由是
想要A类和B类碰撞,A类之间不碰撞,B类之间不碰撞-法1
- 属性值:
- group =0【A的group取-1;B的group取-2】
- CategoryBitmask =0xFFFFFFFF
- ContactTestBitmask=0xFFFFFFFF【AB都取这个值】
- CollisionBitmask =0xFFFFFFFF
- 现象和分析:
- 同类之间不碰撞,a b为同一类物品【group决定的,相同的负的group值的对象不会碰撞;虽然
((a.CategoryBitmask & b.ContactTestBitmask) != 0 || (a.ContactTestBitmask & b.CategoryBitmask) != 0)
等于true,但没碰撞的前提,故无回调】 - 不同类可以碰撞,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为同一类物品【group决定的,相同的负的group值的对象不会碰撞;虽然
想要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】
- 现象和分析:
- 同类之间无碰撞,a b为同一类物品【无碰撞的理由是
(a.CollisionBitmask & b.CategoryBitmask) != 0
false; 无回调是((a.CategoryBitmask & b.CollisionBitmask) != 0 || (a.CollisionBitmask & b.CategoryBitmask) != 0)
等于false故无回调】 - 不同类可以碰撞,a b为不同类的物品【碰撞的理由是
(a.CollisionBitmask & b.CategoryBitmask) != 0
true,b也是;回调理由是有碰撞且((a.CategoryBitmask & b.ContactTestBitmask) != 0 || (a.ContactTestBitmask & b.CategoryBitmask) != 0)
等于true】
- 同类之间无碰撞,a b为同一类物品【无碰撞的理由是
效果图
- 想要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没有碰撞的物理效果*/
- }
- }