解决了环境创建和素材准备和场景之后,我们需要开始研究和解决物理引擎问题。

物理引擎的使用 

为了方便碰撞检测,我使用了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