在Box2D中碰撞事件通过实现b2ContactListener类函数实现,b2ContactListener是Box2D提供的抽象类,它的抽象函数:
virtual void BeginContact(b2Contact* contact)。两个物体开始接触时会响应,但只调用一次。
virtual void EndContact(b2Contact* contact)。分离时响应。但只调用一次。
virtual void PreSolve(b2Contact* contact, const b2Manifold* oldManifold)。持续接触时响应,它会被多次调用。
virtual void PostSolve(b2Contact* contact, const b2ContactImpulse* impulse)。持续接触时响应,调用完preSolve后调用。
下面通过将12.2.3一节的实例采用Box2D技术重构,了解一下Box2d物理引擎中如何检测碰撞。
首先我们需要在工程中添加一个新类。使用Visual Studio 2012中添加一个新类,需要分别添加C++源文件和头文件。具体操作,如图所示,右键点击工程HelloBox2D下的Classes文件夹,在右键菜单中选择,“添加”→ “新项目”。弹出如后面的图所示添加新项对话框,我们在对话框中选择文件的种类,在“名称”中输入文件名ContactListener,然后点击“添加”按钮添加文件。

Visual Studio 2012中添加新类
添加新项对话框

添加完成新类ContactListener,我们还需要修改它的代码,ContactListener.h文件代码如下:

  1. #include "cocos2d.h"
  2. #include "Box2D/Box2D.h"
  3. USING_NS_CC;
  4. class ContactListener : public b2ContactListener
  5. {
  6. private:
  7. //两个物体开始接触时会响应
  8. virtual void BeginContact(b2Contact* contact);
  9. //持续接触时响应
  10. virtual void PreSolve(b2Contact* contact, const b2Manifold* oldManifold);
  11. //持续接触时响应,调用完preSolve后调用
  12. virtual void PostSolve(b2Contact* contact, const b2ContactImpulse* impulse);
  13. //分离时响应
  14. virtual void EndContact(b2Contact* contact);
  15. };
  16. 在头文件中需要引入cocos2d.h和Box2D/Box2D.h头文件,否则会有编译错误。ContactListener采用共有继承b2ContactListener。
  17. ContactListener.cpp文件代码如下:
  18. #include "ContactListener.h"
  19. void ContactListener::BeginContact(b2Contact* contact)                          ①
  20. {
  21. log("BeginContact");
  22. b2Body* bodyA = contact->GetFixtureA()->GetBody();                            ②
  23. b2Body* bodyB = contact->GetFixtureB()->GetBody();                            ③
  24. auto spriteA = (Sprite*)bodyA->GetUserData();                                ④
  25. auto spriteB = (Sprite*)bodyB->GetUserData();                                ⑤
  26. if (spriteA != nullptr && spriteB != nullptr)                                   ⑥
  27. {
  28. spriteA->setColor(Color3B::YELLOW);
  29. spriteB->setColor(Color3B::YELLOW);
  30. }
  31. }
  32. void ContactListener::EndContact(b2Contact* contact)                            ⑦
  33. {
  34. log("EndContact");
  35. b2Body* bodyA = contact->GetFixtureA()->GetBody();
  36. b2Body* bodyB = contact->GetFixtureB()->GetBody();
  37. auto spriteA = (Sprite*)bodyA->GetUserData();
  38. auto spriteB = (Sprite*)bodyB->GetUserData();
  39. if (spriteA != nullptr && spriteB != nullptr)
  40. {
  41. spriteA->setColor(Color3B::WHITE);
  42. spriteB->setColor(Color3B::WHITE);
  43. }
  44. }
  45. void ContactListener::PreSolve(b2Contact* contact, const b2Manifold* oldManifold)           ⑧
  46. {
  47. log("PreSolve");
  48. }
  49. void ContactListener::PostSolve(b2Contact* contact, const b2ContactImpulse* impulse)        ⑨
  50. {
  51. log("PostSolve");
  52. }

上述代码第①行是实现碰撞事件BeginContact函数,第②代码和第③行代码是获得接触双方物体对象。第④代码和第⑤行代码是从物体对象的UserData属性中确定精灵对象,UserData属性可以放置任何对象,这里我们能够通过bodyA->GetUserData()语句取得精灵,那是因为在定义物体的时候通过body->SetUserData(sprite)语句,将精灵放入到物体的UserData属性。第⑥行代码是判断两个精灵是否存在。
代码第⑦行是实现碰撞事件EndContact函数,函数的实现与BeginContact函数类似。第⑧和第⑨行代码是实现碰撞事件PreSolve和PostSolve函数,这两个函数通常用的不多。
我们还需要在要监听事件的层中,添加相关碰撞检测代码。在HelloWorld.h的代码如下:

  1. #ifndef __HELLOWORLD_SCENE_H__
  2. #define __HELLOWORLD_SCENE_H__
  3. #include "cocos2d.h"
  4. #include "Box2D/Box2D.h"
  5. #include "ContactListener.h"                                                ①
  6. #define PTM_RATIO 32
  7. class HelloWorld : public cocos2d::Layer
  8. {
  9. b2World* world;
  10. ContactListener* contactListener;                                           ②
  11. public:
  12. ~HelloWorld();
  13. static cocos2d::Scene* createScene();
  14. virtual bool init();
  15. virtual void update(float dt);
  16. virtual bool onTouchBegan(cocos2d::Touch* touch, cocos2d::Event* event);
  17. CREATE_FUNC(HelloWorld);
  18. void initPhysics();
  19. void addNewSpriteAtPosition(cocos2d::Vec2 p);
  20. };
  21. #endif // __HELLOWORLD_SCENE_H__

上述代码第①行是引入头文件ContactListener.h。第②行代码是声明ContactListener类型的成员变量contactListener。
我们还需要修改HelloWorld.cpp中的HelloWorld::initPhysics()代码如下:

  1. void HelloWorld::initPhysics()
  2. {
  3. … …
  4. contactListener = new ContactListener();
  5. world->SetContactListener(contactListener);
  6. … …
  7. }

函数中的contactListener = new ContactListener()语句是创建ContactListener对象,采用了new关键字分配内存,创建成员变量contactListener,需要自己释放contactListener对象。这些释放过程是在析构函数中进行,它的析构函数代码如下:
HelloWorld::~HelloWorld()
{
    CC_SAFE_DELETE(world);    
CC_SAFE_DELETE(contactListener);
}

使用CC_SAFE_DELETE(contactListener)安全释放contactListener成员变量的内存。

更多内容请关注国内第一本Cocos2d-x 3.2版本图书《Cocos2d-x实战:C++卷》
本书交流讨论网站:http://www.cocoagame.net
更多精彩视频课程请关注智捷课堂Cocos课程:http://v.51work6.com
欢迎加入Cocos2d-x技术讨论群:257760386

欢迎关注智捷iOS课堂微信公共平台

实例介绍Cocos2d-x中Box2D物理引擎:碰撞检测的更多相关文章

  1. 实例介绍Cocos2d-x中Box2D物理引擎:HelloBox2D

    我们通过一个实例介绍一下,在Cocos2d-x 3.x中使用Box2D物理引擎的开发过程,熟悉这些API的使用.这个实例运行后的场景如图所示,当场景启动后,玩家可以触摸点击屏幕,每次触摸时候,就会在触 ...

  2. 实例介绍Cocos2d-x中Box2D物理引擎:使用关节

    下面我们将使用Box2D物理引擎技术进行重构.使得关节能够掌握如何在Box2D使用关节约束.HelloWorldScene.cpp中与使用关节的相关代码如下: void HelloWorld::add ...

  3. 实例介绍Cocos2d-x中Box2D物理引擎:碰撞检測

    在Box2D中碰撞事件通过实现b2ContactListener类函数实现,b2ContactListener是Box2D提供的抽象类,它的抽象函数:virtual void BeginContact ...

  4. cocos2d-x中的Box2D物理引擎

    在Cocos2d-x中集成了2个物理引擎,一个是Chipmunk,一个是Box2D.前者是用C语言编写的,文档和例子相对较少:Box2D是用C++写的,并且有比较完善的文档和资料.所以在需要使用物理引 ...

  5. 瘸腿蛤蟆笔记29-cocos2d-x-3.2 Box2d物理引擎dynamics模块介绍

    转载标明出处:http://blog.csdn.net/notbaron/article/details/38611335 上篇回想 本篇名言:奋斗.寻觅.发现,而不屈服.[诗人丁尼生] 上篇中,我们 ...

  6. libgdx学习记录18——Box2d物理引擎

    libgdx封装了Box2D物理引擎,通过这个引擎能够模拟物理现实,使设计出的游戏更具有真实感. libgdx中,Box2d程序的大概过程: 1. 创建物理世界world,并设置重力加速度. 2. 创 ...

  7. python下的Box2d物理引擎的配置

    /******************************* I come back! 由于已经大四了,正在找工作 导致了至今以来第二长的时间内没有更新博客.向大家表示道歉 *********** ...

  8. 【极客学院出品】Cocos2d-X系列课程之九-BOX2D物理引擎

    Cocos2d-x 是时下最热门的手游引擎,在国内和国外手机游戏开发使用的份额各自是70%和25%,在App Store的top10中,有7个是用它开发的. 本节课程为Cocos2d-x系列课程之九, ...

  9. cocos2d-js中Chipmunk物理引擎相关(1)

    近期看些cocos2d-js的东西.用到当中的Chipmunk的一些东西.由于相关的资料也不是非常具体,所以看到一些东西实用就记录下来. 1. chipmunk是cocos2d的一个一个物理引擎.用来 ...

随机推荐

  1. DynamoDB Local for Desktop Development

    Would you like to be able to write and test code that uses the Amazon DynamoDB API even if you have ...

  2. Codeforces Gym 100431G Persistent Queue 可持久化队列

    Problem G. Persistent QueueTime Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://acm.hust.edu.cn/vjudg ...

  3. delphi 添加节点

      //在选中的节点中上添加1个节点 procedure TForm1.Button1Click(Sender: TObject); begin     with TreeView1 do     b ...

  4. MYSQL 备份工具

    backup of a database is a very important thing. If no backup, meet the following situation goes craz ...

  5. Uploadify帮助文档

    auto 当文件被添加到队列时,自动上传. (字符串) buttonImg 浏览按钮的背景图片路径. (字符串) buttonText 默认在按钮上显示的文本. (字符串) cancelImg 取消按 ...

  6. 小白日记14:kali渗透测试--NMAP

    NAMP 被认为是最强大的扫描器 所有参数 root@kali:~# nmap Nmap 7.01 ( https://nmap.org ) Usage: nmap [Scan Type(s)] [O ...

  7. HBase-配置说明

    转载自:http://www.aboutyun.com/thread-7914-1-1.html hbase.rootdir这个目录是region  server的共享目录,用来持久化Hbase.UR ...

  8. Destroying the bus stations

    Destroying the bus stations Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 1832   Acce ...

  9. Android(java)学习笔记83:finally关键字的作用

    package cn.itcast_07; import java.text.ParseException; import java.text.SimpleDateFormat; import jav ...

  10. 在SSIS 的 64 位版本中不支持 Excel 连接管理器

    Microsoft sql server 2008 R2——> SQL SERVER Business Intelligence Development Studio 使用EXCEL数据源或目标 ...