关于cocos2dx 3.3出的physics物理引擎,如果想处理两个body碰撞一般作法都是先设置好各自Body的三个掩码,然后再在游戏场景里注册物理碰撞侦听器,然后调用onContactBegin处理,如下:
金币的
void Coin::initBody()
{
auto phyBody = PhysicsBody::createEdgeBox(getSprite()->getContentSize());
phyBody->setCategoryBitmask(1);
phyBody->setCollisionBitmask(1);
phyBody->setContactTestBitmask(1);
this->setPhysicsBody(phyBody);
}
人的:
auto runerBody = PhysicsBody::createBox(bodySize, material);
//设置碰撞检测参数
runerBody->setCategoryBitmask(1);
runerBody->setCollisionBitmask(1);
runerBody->setContactTestBitmask(1);
//绑定刚体
this->setPhysicsBody(runerBody);
然后在游戏场景里注册碰撞侦听器
void PlayScene::onEnter()
{
Layer::onEnter();
//注册物理碰撞
auto contactListener = EventListenerPhysicsContact::create();
contactListener->onContactBegin = CC_CALLBACK_1(PlayScene::onContactBegin, this);
_eventDispatcher->addEventListenerWithSceneGraphPriority(contactListener, this);
}
然后在onContactBegin里处理碰撞就行了:
bool PlayScene::onContactBegin(cocos2d::PhysicsContact& contact)
{
auto body_1 = (Sprite*)contact.getShapeA()->getBody()->getNode(); //发生碰撞的物体1
auto body_2 = (Sprite*)contact.getShapeB()->getBody()->getNode(); //发生碰撞的物体2
//金币消失
if (body_1->getTag() == coinTag){
body_1->setVisible(false);
}
if (body_2->getTag() == coinTag){
body_2->setVisible(false);
}
return false;
}
看上去很简单,但是那三个掩码:
setCategoryBitmask,setCollisionBitmask,setContactTestBitmask是什么意思呢?看了官方的文档,注释,还有不知其数的介绍物理引擎大神的文章,还是一头雾水不知所以。一般为了省事,都把这三个掩码设为1,这样不论什么物体都会发生碰撞,也能响应处理函数,但是这样做真的好吗?所谓不求甚解只求洒脱可能就是这个意思,但这可不是什么好的治学态度,也正是国人从古到今这个态度造就了我国自古以来就诞生不了科学这种奇葩景象还不以为耻反以为荣到现在沦落为到处抱别人大腿求施舍的窘境...
CategoryBitmask好理解,表示一个物体所属哪个类别
可是CollisionBitmask和ContactTestBitmask就不好理解了,官方文档解释为前者与category掩码相与是否为1表示是否能发生碰撞,contactTest掩码与category掩码相于是否为1决定了是与能产生碰撞响应.... 这是什么话,我翻来覆去怎么看都觉得说了半天都是一个意思嘛!都是是否能产生碰撞响应。到底有什么区别呢?
后来经过我不断的尝试修改,终于搞明白两者含义的区别:
setCategoryBitmask,setCollisionBitmask决定了是否能产生碰撞。产生碰撞和发生碰撞响应是不同的概念。如人物奔跑时碰到了金币,这里如果没有碰撞处理函数,且把什么掩码都设为1,那么你会发现角色碰到金币时角色不再向前移动了,金币成了一个挡在路上的砖块,这时已经发生了碰撞 了,但如果你把人的类别设为1,金币的类别设为0,而两者的CollisionBitmask都为1,则金币和人的CategoryBitmask和CollisionBitmask掩码相与为0,则不会发生碰撞,在游戏里效果就是人奔跑时穿过了金币,金币就像空气一样,这就是没有发生碰撞的含义。
那么ContactTestBitmask呢,这个参数决定了是否能触发碰撞响应函数onContactBegin. 有些碰撞我们是不想处理的,如人物从空中落到一块大石头上,落到石头上只须停在石头上就行了,不需要做什么特殊的处理,这时你只需要将地面的类别设为0,人的类别设为1,ContactTestBitmask都设为1,这样相与的结果为0,就不会触发onContactBegin函数。那你该问了,你不处理那人怎么会停在石头上而不掉下去?不用担心,这是物理引擎的事,也正是物理引擎的强大之处,我们只要设置了刚体body就可以很轻松的写出一个像超级马里奥那种平台跳跃游戏也不需要判断马里奥脚上是否踩到地啦?跳的时候是不是头顶到地板啦?这种种复杂的情况,一个精灵设置了body,它就是一个硬硬的砖头,你只要掩码设好无论如何也穿不过去的。回到刚才人碰到金币的例子,如金币这种我们希望人碰到金币就Money + 1,并且金币消失,那么,就把金币和人的不论类别掩码还是ContactTest掩码都设为1,这样就瞎猫碰到死耗子一样触发了碰撞响应函数,在响应函数里再设置人的money++并且金币消失,也就达到了我们的效果