解决了环境创建和素材准备和场景之后,我们需要开始研究和解决物理引擎问题。
物理引擎的使用
为了方便碰撞检测,我使用了Cocos2d-x集成的物理引擎,Cocos2d-x有两种物理引擎,一种轻量级的Chipmunk,一种相对Chipmunk比较复杂的Box2d,在3.x版本Cocos2d-x封装了Chipmunk的api,简单好用,在项目中就是使用了这种物理引擎。
物理引擎的使用:
1、设置物理世界的场景。
2、设置物体形状(在物理世界的一个实体)和碰撞属性
3、碰撞检测
这样,我们就可以轻松使用Cocos2d-x的物理引擎了。
上面物理引擎的使用我是这样理解的,设置了物理世界的场景后,相当于我们创造了一个屏幕大小的世界,精灵在上面只是灵魂的存在,任何物体互相之间是无法影响的,就是相当于敌机要撞上我机时,他是穿过去的!!!没错。就是这样。但是当我们给他设置物理形状时,那么就等于他在世界上有个了尸体,啊打错不好意思,是实体。实体什么概念,就是前面有道墙,你优哉游哉得以为像演电影一样穿过去,最后碰个头破血流。没错,实体就是这概念,物理世界就是这概念(解释生动具体吧,嘿嘿,你又想动手吗)。简单得说就是模拟物理世界。另外可以设置实体的各种属性,比如受重力影响啦,密度啦,重量啦等等,然后在物理世界模拟物理运行,想想就有点酷炫,感兴趣去玩一下。
下面是具体代码
1、设置物理世界场景
1
2
3
|
auto scene = Scene::createWithPhysics(); //这里是关键代码,只需要一句,即可设置物理世界场景。
PhysicsWorld* phyWorld = scene->getPhysicsWorld(); //获取物理世界对象,通过它来设置和获取物理世界的各种属性
phyWorld->setDebugDrawMask(PhysicsWorld::DEBUGDRAW_ALL); //设置为物理世界的物体可见
|
2、设置物体形状
1
2
3
4
5
|
auto planeBody = PhysicsBody::createBox(plane->getContentSize()); //这个create是设置的刚体为矩形,也可以为其他形状。
planeBody->setContactTestBitmask(0x0003); //碰撞测试掩码
planeBody->setCategoryBitmask(0x0001); //类别掩码
planeBody->setCollisionBitmask(0x0007) //碰撞掩码
plane->setPhysicsBody(planeBody); //把物体设置为实体
|
下面简述下三个掩码的作用
刚开始看书的时候可能书讲得太片面了,有些误解,然后就各种坑。其实三个掩码决定的是物体是否可以相互碰撞,然后是否触发碰撞事件。
没错,三个掩码决定的东西,别想得这么简单,大有文章在里面。
他是如何决定碰撞的呢?
A 相与 B result 是否会碰撞 是否触发事件
CategoryBitmask & CollisionBitmask 零 不会 否
CategoryBitmask & CollisionBitmask 非零 会 否
ContactTestBitmask & CollisionBitmask 零 不会 会
上面的表格就是说,决定是否会碰撞的是CategoryBitmask和CollisionBitmask (不管是A的CategoryBitmask还是B的CategoryBitmask,只要与另个物体的CollisionBitmask为零就不会碰撞,所以计算物体的掩码的时候靠的是这个等式A&B是否等于零的等式,这里也有个坑)
而决定在碰撞的时候触发碰撞事件的是ContactTestBitmask和CollisionBitmask
对于这三个码的作用,最好是亲力亲为,感受下它的坑有多深。
CategoryBitmask值为0xFFFFFFFF,ContactTestBitmask值是00000000,而CollisionBitmask值为0xFFFFFFFF,表示所有的身体会相互碰撞,但默认不发送接触事件。
另外就是三个码的设置,才能让程序的逻辑正确执行。就像我们项目中,有我机,敌机,和子弹三个实体,我机和敌机可以碰撞,我机不可以和子弹碰撞,子弹可以和敌机碰撞。九个码,要决定这个逻辑,那么就有九元一次方程给你解,这也是个坑,只能放值进去算了。到现在,敌机和敌机不能碰撞这个逻辑我还没通过掩码实现,现在的话,敌机和敌机碰撞在一起,还会触发事件,是个bug,不过在程序中使用了点逻辑跳过了。具体看代码。再算下去头疼,不知道各位大神有何好的方法计算。
3、碰撞检测
碰撞检测交给了引擎去做了,现在我们只剩下了碰撞事件监听还有处理。看代码:
1
2
3
4
5
6
7
8
9
10
11
|
auto listener = EventListenerPhysicsContact::create();
listener -> onContactBegin = [=](PhysicsContact& contact)
{
//do something
//通过下面语句获取碰撞的两个节点
auto spriteA = (Sprite *)contact.getShapeA()->getBody()->getNode();
auto spriteB = (Sprite *)contact.getShapeB()->getBody()->getNode();
}
//注册监听器
EventDispatcher * eventDispatcher = Director::getInstance()->getEventDispatcher();
eventDispatcher ->addEventListenerWithSceneGraphPriority(listener,this);
|
这样,只要实体碰撞到了一起,就会触发该函数,还有其他函数,比如onContactPreSolve,onContactPostSolve和onContactSeperate,看函数名大概也可以猜到它是干嘛的了。
下一节我们将会利用物理引擎构建我们的飞机大战游戏了。
相关教程:
Cocos2d-x 3.x《飞机大战》教程1:环境与创建项目 https://www.taikr.com/article/1587
Cocos2d-x 3.x《飞机大战》教程2:素材准备与游戏菜单场景
https://www.taikr.com/article/1589
Cocos2d-x 3.x《飞机大战》教程4:游戏场景
https://www.taikr.com/article/1591
Cocos2d-x 3.x《飞机大战》教程5:敌我碰撞处理、分数计算、音乐播放 https://www.taikr.com/article/1592
Cocos2d-x 3.x《飞机大战》教程6:游戏结束场景 https://www.taikr.com/article/1593