事实上我也非常吃惊…居然写到第七篇了,我估计也就是四篇的内容,感觉非常奇妙,我也不会非常唠叨什么吖(小若:32个喷!

),怎么都到第七篇了。

笨木头花心贡献,啥?花心?不呢,是用心~

转载请注明,原文地址: http://www.benmutou.com/blog/archives/920

文章来源:笨木头与游戏开发

碰撞监听

首先,确保我们创建物理对象的时候,给对象设置了碰撞条件(假设你是一步步按着教程来写的代码,那就是设置好了):

  1. body->setCategoryBitmask(1);    // 0001
  2. body->setCollisionBitmask(1);   // 0001
  3. body->setContactTestBitmask(1); // 0001

这样我们才干监听到它们的碰撞事件,至于原理。就不说了。以我的唠叨程度,不是一两篇内容能说完的。

然后。我们给TollgateScene加入一个函数声明:

  1. /* 碰撞检測 */
  2. bool onContactBegin(PhysicsContact& contact);

这是碰撞事件開始时的回调函数,监听碰撞事件非常easy。我们修改一下TollgateScene的init函数:

  1. bool TollgateScene::init()
  2. {
  3. if (!Layer::init())
  4. {
  5. return false;
  6. }
  7. /* 创建主角 */
  8. Size visibleSize = Director::getInstance()->getVisibleSize();
  9. m_player = Player::create();
  10. m_player->setPosition(Point(visibleSize.width * 0.5f, visibleSize.height * 0.85f));
  11. this->addChild(m_player, 5);
  12. /* 创建操作UI */
  13. createOprUI();
  14. /* 碰撞监听 */
  15. auto contactListener = EventListenerPhysicsContact::create();
  16. contactListener->onContactBegin = CC_CALLBACK_1(TollgateScene::onContactBegin, this);
  17. _eventDispatcher->addEventListenerWithSceneGraphPriority(contactListener, this);
  18. this->schedule(schedule_selector(TollgateScene::logic));
  19. return true;
  20. }

流程就是这样:

1. 创建EventListenerPhysicsContact对象,能够看做是碰撞监听回调接口

2. 绑定onContactBegin事件的回调函数

3. 将监听接口加入到统一的事件派发器里(addEventListenerWithSceneGraphPriority)

Cocos2d-x3.0的监听事件修改非常大(但非常好用)。这里就不多解释了,网上非常多文章有介绍。

假设大家有去看看EventListenerPhysicsContact的源代码的话,会发现,碰撞事件不仅仅仅仅有onContactBegin一个,其它的事件我就不说了。这里仅仅是要onContactBegin。作用是在两个物理对象開始发生碰撞的时候调用。

好,最后看看onContactBegin函数实现:

  1. bool TollgateScene::onContactBegin(PhysicsContact& contact)
  2. {
  3. auto nodeA = (Sprite*)contact.getShapeA()->getBody()->getNode();
  4. auto nodeB = (Sprite*)contact.getShapeB()->getBody()->getNode();
  5. return true;
  6. }

当中获取到的nodeA和nodeB就是发生碰撞的两个节点对象。

如今。看看碰撞检測是否正常吧。用调试模式执行游戏。然后在onContactBegin函数里打个断点,看看主角碰到墙的时候有没有进入这个断点吧~

假设有,那就代表成功了。

然后,另一点别忘了,在TollgateScene的onExit函数里,把监听事件给取消了:

  1. void TollgateScene::onExit()
  2. {
  3. Layer::onExit();
  4. _eventDispatcher->removeEventListenersForTarget(this);
  5. }

怎么知道发生碰撞的两个节点各自是谁?

如今我们仅仅知道有两个节点碰撞了。也能取到两个节点对象,可是,它们都是谁啊?根本不认识啊。那怎么进行下一步操作呢?我想给Player对象加血,那怎么办呢?

没关系,节点有一个非常万能的函数:setTag。

给节点设置Tag可不是仅仅用来从Layer里获取子节点对象。我们还能够用来区分这些节点是谁,应该是。区分这些节点是属于哪一类东西。

创建一个生物分类表

好。是时候新建一个头文件了,为了迎合这份高大上的教程,我们就称之为生物分类表吧~

创建一个头文件,命名为ObjectTag.h,内容例如以下:

  1. #ifndef ObjectTag_H
  2. #define ObjectTag_H
  3. #define ObjectTag_Player 1
  4. #define ObjectTag_Border 2
  5. #define ObjectTag_Monster 3
  6. #endif

这大实用处,别着急~

给各种物体设置Tag吧

好了,如今我们要给主角和墙(或者称之为锯齿)设定生物类别了。在Player的init函数的最后加上一句代码:

  1. bool Player::init()
  2. {
  3. /* 这里省略了非常多代码 */
  4. this->setTag(ObjectTag_Player);
  5. return true;
  6. }

当然,ObjectTag.h头文件也别忘了加上。

然后。给BackgroundLayer的createBorder函数最后也加上一句代码:

  1. Sprite* BackgroundLayer::createBorder(Point pos)
  2. {
  3. /* 这里省略了非常多代码 */
  4. border->setTag(ObjectTag_Border);
  5. return border;
  6. }

開始区分谁是谁

OK了,主角和墙都有了各自的生物类型了~如今我们能够区分碰撞的两个对象各自是谁了。

我们要在TollgateScene的onContactBegin函数里做处理:

  1. bool TollgateScene::onContactBegin(PhysicsContact& contact)
  2. {
  3. auto nodeA = (Sprite*)contact.getShapeA()->getBody()->getNode();
  4. auto nodeB = (Sprite*)contact.getShapeB()->getBody()->getNode();
  5. if (nodeA == NULL || nodeB == NULL)
  6. {
  7. return true;
  8. }
  9. Node* playerNode = NULL;    /* 玩家对象 */
  10. Node* other = NULL;         /* 怪物或墙等其它对象 */
  11. if (nodeA->getTag() == ObjectTag_Player)
  12. {
  13. playerNode = nodeA;
  14. other = nodeB;
  15. }
  16. else if (nodeB->getTag() == ObjectTag_Player)
  17. {
  18. playerNode = nodeB;
  19. other = nodeA;
  20. }
  21. else
  22. {
  23. /* 假设两个碰撞的物体中,不存在玩家对象,就忽略,不做处理 */
  24. return true;
  25. }
  26. Player* player = (Player*)playerNode;
  27. /* 碰撞到边缘锯齿(墙),+1血 */
  28. if (other->getTag() == ObjectTag_Border)
  29. {
  30. /* 扣-1血。就相当于加1血 */
  31. player->beAtked(-1);
  32. log("player cur HP:%d", player->getiHP());
  33. }
  34. return true;
  35. }

(小若:这么长的代码。打死我我也不看~!

这段代码要做的事情事实上非常easy,萝莉一下,萝莉、罗莉。罗列,嗯(这输入法坏了,一定是):

1.推断nodeA的Tag是不是ObjectTag_Player,假设是。那么nodeA就是Player对象了,同一时候。nodeB仅仅能是墙或者是怪物对象了(由于游戏里仅仅有一个Player对象)

2.假设nodeA不是Player,那就继续推断nodeB

3.假设nodeA和nodeB都不是Player对象,那我们就不做处理。由于怪物和怪物之间的碰撞不须要做处理

4.假设找到Player对象,那就推断other对象是不是墙,是的话。那就让Player加1滴血

5.由于这个实例缺少非常多功能,比方UI、数据绑定、碰撞时产生的动画效果之类的。所以没法直观地看到Player加血的动作,仅仅好用打印日志的方式来查看了。

有朋友提醒我漏了解说Player的beAtked函数,这里补充一下。如代码:

  1. void Player::beAtked(int iValue)
  2. {
  3. if (iValue < 0)
  4. {
  5. cure(-iValue);
  6. }
  7. else
  8. {
  9. hurt(std::abs(iValue));
  10. }
  11. }
  12. void Player::hurt(int iValue)
  13. {
  14. setiHP(getiHP() - iValue);
  15. }
  16. void Player::cure(int iValue)
  17. {
  18. setiHP(getiHP() + iValue);
  19. }

好了,如今用调试模式执行游戏(键盘F5),使劲让主角撞墙吧。然后看看日志输出:

player cur HP:101

player cur HP:102

player cur HP:103

player cur HP:104

player cur HP:105

player cur HP:106

player cur HP:107

player cur HP:108

player cur HP:109

假设有相似以上的日志输出。那就证明我们成功了~

Cocos2d-x3.0游戏实例之《别救我》第七篇——物理世界的碰撞检測的更多相关文章

  1. cocos2d-x 3.0游戏实例学习笔记 《跑酷》第七步--物理碰撞检測(1)

    说明:这里是借鉴:晓风残月前辈的博客,他是将泰然网的跑酷教程,用cocos2d-x 2.X 版本号重写的,眼下我正在学习cocos2d-X3.0 于是就用cocos2d-X 3.0重写,并做相关笔记 ...

  2. Cocos2d-x3.0游戏实例《不要救我》第十篇(结束)——使用Json配置数据类型的怪物

    如今我们有2种类型的怪物,并且创建的时候是写死在代码里的,这是要作死的节奏~ 所以.必须可配置.不然会累死人的. ; i < size; ++i) { int id = root[i][&quo ...

  3. Cocos2d-x3.0游戏实例《不要救我》第一章——前言

    我们可以学习? 这是一个非常easy游戏.但更多的东西用(对于初学者).至少,对于它的一个例子,有点多. 笨木头花心贡献.啥?花心?不呢.是用心~ 转载请注明,原文地址:http://www.benm ...

  4. Cocos2d-x3.0游戏实例《不要救我》三——背景滚动周期

    好.让我们来解释一下这个无限循环滚动的背景.这方面的知识一直讲到烂.我以前的文章还介绍了.所以不是那么特别清楚. 笨木头花心贡献,啥?花心?不呢,是用心~ 转载请注明,原文地址:http://www. ...

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

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

  6. Cocos2d-x3.0游戏实例之《别救我》第六篇——从代码中获取UI控件

    这篇的内容非常easy,获取UI控件,然后使用它. 还记得我们在UI编辑器中给三个button分别命名了吧? 如今要用上了. 笨木头花心贡献,啥?花心?不呢,是用心~ 转载请注明,原文地址: http ...

  7. Cocos2d-x3.0游戏实例之《别救我》第八篇——TiledMap实现关卡编辑器

    版权声明:本文为博主原创文章,未经博主同意不得转载. https://blog.csdn.net/musicvs/article/details/25368273 好吧.我真心全然搞不懂.我如今仅仅只 ...

  8. Cocos2d-x3.0游戏实例之《别救我》第二篇——创建物理世界

    这篇我要给大家介绍两个知识点: 1. 创建游戏物理世界 2. 没了(小若:我噗) 害怕了?不用操心.这太简单了~! 笨木头花心贡献.啥?花心?不呢.是用心~ 转载请注明,原文地址:http://www ...

  9. cocos2d-x ios游戏开发初认识(八) 触摸事件与碰撞检測

    玩过植物大战僵尸都知道,要在草坪里放一朵向日葵或者其他的植物仅仅需触摸那个植物将其拖入到想要摆放的位置,这事实上就是这节要写的触摸事件.还能够发现当我们的僵尸出来的时候,我们的小豌豆会发子弹攻击僵尸, ...

随机推荐

  1. C#获取网页信息核心方法(入门一)

    目录:信息采集入门系列目录 下面记录的是我自己整理的C#请求页面核心类,主要有如下几个方法 1.HttpWebRequest Get请求获得页面html 2.HttpWebRequest Post请求 ...

  2. 我一直记不住的vim用法

    一.多行编辑进入visual block模式一般模式下Crtl+v组合键以块的形式选中待编辑的文本 进入visual line模式一般模式下大写V以行的形式选中待编辑的文本 上述两种模式的复制用y,删 ...

  3. go chapter 4 - 不定长参数

    https://www.cnblogs.com/chase-wind/p/5644838.html 空接口可以指向任何数据对象,所以可以使用interface{}定义任意类型变量,同时interfac ...

  4. Codeforces Round #425 (Div. 2) Misha, Grisha and Underground(LCA)

    Misha, Grisha and Underground time limit per test 2 seconds memory limit per test 256 megabytes inpu ...

  5. Flask实战第55天:cms轮播图上传到七牛功能完成

    登录七牛云,进入“对象存储”, 新建存储空间(Bucket), 我创建的空间命名为flask-bbs 创建完Bucket,七牛会给我们提供一个测试域名,生产环境中,我们需要绑定自己的域名 在个人面板中 ...

  6. 29、Flask实战第29天:cms用户名渲染和注销功能实现

    这节来完成用户名渲染和注销的功能,目前用户名在前端页面是写死的,我们需要动态的展示出来 用户名渲染 实现用户名动态展示,其中一种方法就是在视图函数,根据session信息,获取到user id,通过该 ...

  7. 持续获取password

    function GetPasswd { RunCounter=1 DB_PSSWD=getpassword while [ -z "${DB_PSSWD}" -a ${RunCo ...

  8. NOIP 2006 提高组 t1 能量项链

    题目描述 在Mars星球上,每个Mars人都随身佩带着一串能量项链.在项链上有N颗能量珠.能量珠是一颗有头标记与尾标记的珠子,这些标记对应着某个正整数.并且,对于相邻的两颗珠子,前一颗珠子的尾标记一定 ...

  9. Codeforces 379 F. New Year Tree

    \(>Codeforces \space 379 F. New Year Tree<\) 题目大意 : 有一棵有 \(4\) 个节点个树,有连边 \((1,2) (1,3) (1,4)\) ...

  10. [BZOJ1563][NOI2009]诗人小G(决策单调性优化DP)

    模板题. 每个决策点都有一个作用区间,后来的决策点可能会比先前的优.于是对于每个决策点二分到它会比谁在什么时候更优,得到新的决策点集合与区间. #include<cstdio> #incl ...