Cocos2d-x 3.x《飞机大战》教程3:物理引擎的使用

2015年03月18日 10:00 0 点赞 0 评论 更新于 2017-05-07 02:45

在完成环境创建、素材准备和场景搭建之后,我们将开始研究并解决物理引擎的相关问题。

物理引擎的选择与使用概述

为了方便进行碰撞检测,我们选用了 Cocos2d-x 集成的物理引擎。Cocos2d-x 提供了两种物理引擎,一种是轻量级的 Chipmunk,另一种是相对复杂的 Box2d。在 3.x 版本中,Cocos2d-x 对 Chipmunk 的 API 进行了封装,使用起来简单便捷,因此本项目采用了这种物理引擎。

使用 Cocos2d-x 的物理引擎主要分为以下三个步骤:

  1. 设置物理世界的场景。
  2. 设置物体形状(物理世界中的实体)和碰撞属性。
  3. 进行碰撞检测。

下面我们详细介绍每个步骤。

1. 设置物理世界场景

设置物理世界场景的关键代码如下:

auto scene = Scene::createWithPhysics();
// 这里是关键代码,只需要一句,即可设置物理世界场景。
PhysicsWorld* phyWorld = scene->getPhysicsWorld();
// 获取物理世界对象,通过它来设置和获取物理世界的各种属性
phyWorld->setDebugDrawMask(PhysicsWorld::DEBUGDRAW_ALL);
// 设置为物理世界的物体可见

通过上述代码,我们创建了一个带有物理世界的场景,并获取了物理世界对象,同时开启了物理物体的调试绘制功能,方便我们观察物理物体的状态。

2. 设置物体形状

设置物体形状的代码示例如下:

auto planeBody = PhysicsBody::createBox(plane->getContentSize());
// 这个 create 是设置的刚体为矩形,也可以为其他形状。
planeBody->setContactTestBitmask(0x0003);
// 碰撞测试掩码
planeBody->setCategoryBitmask(0x0001);
// 类别掩码
planeBody->setCollisionBitmask(0x0007);
// 碰撞掩码
plane->setPhysicsBody(planeBody);
// 把物体设置为实体

三个掩码的作用

刚开始学习时,可能会因为书中的讲解不够全面而产生误解,进而陷入各种问题。实际上,这三个掩码决定了物体是否可以相互碰撞以及是否触发碰撞事件,其中大有学问。

三个掩码是如何决定碰撞的呢?具体规则如下: | 相与操作 | 结果 | 是否会碰撞 | 是否触发事件 | | --- | --- | --- | --- | | CategoryBitmask & CollisionBitmask = 零 | 零 | 不会 | 否 | | CategoryBitmask & CollisionBitmask ≠ 零 | 非零 | 会 | 否 | | ContactTestBitmask & CollisionBitmask = 零 | 零 | 不会 | 会 |

简单来说,决定是否会碰撞的是 CategoryBitmaskCollisionBitmask(不管是 A 的 CategoryBitmask 还是 B 的 CategoryBitmask,只要与另一个物体的 CollisionBitmask 相与结果为零就不会碰撞,计算物体的掩码时依靠的就是 A&B 是否等于零这个等式,这里需要特别注意);而决定在碰撞时是否触发碰撞事件的是 ContactTestBitmaskCollisionBitmask

例如,当 CategoryBitmask 值为 0xFFFFFFFFContactTestBitmask 值是 00000000CollisionBitmask 值为 0xFFFFFFFF 时,表示所有的物体都会相互碰撞,但默认不发送接触事件。

在实际项目中,合理设置这三个掩码才能保证程序逻辑的正确执行。例如在我们的飞机大战项目中,有我方飞机、敌机和子弹三个实体,要求我方飞机和敌机可以碰撞,我方飞机和子弹不能碰撞,子弹可以和敌机碰撞。要通过九个掩码来实现这个逻辑并非易事,就像解九元一次方程一样。目前,敌机和敌机不能碰撞这个逻辑还未通过掩码完全实现,在程序中暂时使用了一些逻辑来跳过这个问题。希望各位大神能分享更好的计算方法。

3. 碰撞检测

碰撞检测由引擎负责,我们只需要进行碰撞事件的监听和处理。代码如下:

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);

当实体发生碰撞时,onContactBegin 函数会被触发。此外,还有 onContactPreSolveonContactPostSolveonContactSeperate 等函数,从函数名大致可以推测出它们的作用。

总结与后续安排

通过以上步骤,我们可以轻松使用 Cocos2d-x 的物理引擎。下一节我们将利用物理引擎构建飞机大战游戏。

相关教程

作者信息

boke

boke

共发布了 1025 篇文章