Cocos2d-x3.0游戏实例之《别救我》第七篇——物理世界的碰撞检测
2014-05-08 10:00
766 查看
其实我也很惊讶…竟然写到第七篇了,我预计也就是四篇的内容,感觉很神奇,我也不会很唠叨什么吖(小若:32个喷!),怎么都到第七篇了。 笨木头花心贡献,啥?花心?不呢,是用心~转载请注明,原文地址: http://www.benmutou.com/blog/archives/920文章来源:笨木头与游戏开发
好了,现在用调试模式运行游戏(键盘F5),使劲让主角撞墙吧,然后看看日志输出:player cur HP:101player cur HP:102player cur HP:103player cur HP:104player cur HP:105player cur HP:106player cur HP:107player cur HP:108player cur HP:109 如果有类似以上的日志输出,那就证明我们成功了~
碰撞监听
首先,确保我们创建物理对象的时候,给对象设置了碰撞条件(如果你是一步步按着教程来写的代码,那就是设置好了):body->setCategoryBitmask(1); // 0001 body->setCollisionBitmask(1); // 0001 body->setContactTestBitmask(1); // 0001这样我们才能监听到它们的碰撞事件,至于原理,就不说了,以我的唠叨程度,不是一两篇内容能说完的。 然后,我们给TollgateScene添加一个函数声明:
/* 碰撞检测 */ bool onContactBegin(PhysicsContact& contact);这是碰撞事件开始时的回调函数,监听碰撞事件很简单,我们修改一下TollgateScene的init函数:
bool TollgateScene::init() { if (!Layer::init()) { return false; } /* 创建主角 */ Size visibleSize = Director::getInstance()->getVisibleSize(); m_player = Player::create(); m_player->setPosition(Point(visibleSize.width * 0.5f, visibleSize.height * 0.85f)); this->addChild(m_player, 5); /* 创建操作UI */ createOprUI(); /* 碰撞监听 */ auto contactListener = EventListenerPhysicsContact::create(); contactListener->onContactBegin = CC_CALLBACK_1(TollgateScene::onContactBegin, this); _eventDispatcher->addEventListenerWithSceneGraphPriority(contactListener, this); this->schedule(schedule_selector(TollgateScene::logic)); return true; }流程就是这样:1. 创建EventListenerPhysicsContact对象,可以看做是碰撞监听回调接口2. 绑定onContactBegin事件的回调函数3. 将监听接口添加到统一的事件派发器里(addEventListenerWithSceneGraphPriority) Cocos2d-x3.0的监听事件改动很大(但很好用),这里就不多解释了,网上很多文章有介绍。 如果大家有去看看EventListenerPhysicsContact的源码的话,会发现,碰撞事件不仅仅只有onContactBegin一个,其他的事件我就不说了。这里只是要onContactBegin,作用是在两个物理对象开始发生碰撞的时候调用。 好,最后看看onContactBegin函数实现:
bool TollgateScene::onContactBegin(PhysicsContact& contact) { auto nodeA = (Sprite*)contact.getShapeA()->getBody()->getNode(); auto nodeB = (Sprite*)contact.getShapeB()->getBody()->getNode(); return true; }其中获取到的nodeA和nodeB就是发生碰撞的两个节点对象。现在,看看碰撞检测是否正常吧,用调试模式运行游戏,然后在onContactBegin函数里打个断点,看看主角碰到墙的时候有没有进入这个断点吧~如果有,那就代表成功了。 然后,还有一点别忘了,在TollgateScene的onExit函数里,把监听事件给取消了:
void TollgateScene::onExit() { Layer::onExit(); _eventDispatcher->removeEventListenersForTarget(this); }
怎么知道发生碰撞的两个节点分别是谁?
现在我们只知道有两个节点碰撞了,也能取到两个节点对象,但是,它们都是谁啊?根本不认识啊,那怎么进行下一步操作呢?我想给Player对象加血,那怎么办呢? 没关系,节点有一个很万能的函数:setTag。给节点设置Tag可不是仅仅用来从Layer里获取子节点对象,我们还可以用来区分这些节点是谁,应该是,区分这些节点是属于哪一类东西。创建一个生物分类表
好,是时候新建一个头文件了,为了迎合这份高大上的教程,我们就称之为生物分类表吧~创建一个头文件,命名为ObjectTag.h,内容如下:#ifndef ObjectTag_H #define ObjectTag_H #define ObjectTag_Player 1 #define ObjectTag_Border 2 #define ObjectTag_Monster 3 #endif这大有用处,别着急~
给各种物体设置Tag吧
好了,现在我们要给主角和墙(或者称之为锯齿)设定生物类别了,在Player的init函数的最后加上一句代码:bool Player::init() { /* 这里省略了很多代码 */ this->setTag(ObjectTag_Player); return true; }当然,ObjectTag.h头文件也别忘了加上。 然后,给BackgroundLayer的createBorder函数最后也加上一句代码:
Sprite* BackgroundLayer::createBorder(Point pos) { /* 这里省略了很多代码 */ border->setTag(ObjectTag_Border); return border; }
开始区分谁是谁
OK了,主角和墙都有了各自的生物类型了~现在我们可以区分碰撞的两个对象分别是谁了。 我们要在TollgateScene的onContactBegin函数里做处理:bool TollgateScene::onContactBegin(PhysicsContact& contact) { auto nodeA = (Sprite*)contact.getShapeA()->getBody()->getNode(); auto nodeB = (Sprite*)contact.getShapeB()->getBody()->getNode(); if (nodeA == NULL || nodeB == NULL) { return true; } Node* playerNode = NULL; /* 玩家对象 */ Node* other = NULL; /* 怪物或墙等其他对象 */ if (nodeA->getTag() == ObjectTag_Player) { playerNode = nodeA; other = nodeB; } else if (nodeB->getTag() == ObjectTag_Player) { playerNode = nodeB; other = nodeA; } else { /* 如果两个碰撞的物体中,不存在玩家对象,就忽略,不做处理 */ return true; } Player* player = (Player*)playerNode; /* 碰撞到边缘锯齿(墙),+1血 */ if (other->getTag() == ObjectTag_Border) { /* 扣-1血,就相当于加1血 */ player->beAtked(-1); log("player cur HP:%d", player->getiHP()); } return true; }(小若:这么长的代码,打死我我也不看~!) 这段代码要做的事情其实很简单,萝莉一下,萝莉、罗莉,罗列,嗯(这输入法坏了,一定是):1.判断nodeA的Tag是不是ObjectTag_Player,如果是,那么nodeA就是Player对象了,同时,nodeB只能是墙或者是怪物对象了(因为游戏里只有一个Player对象)2.如果nodeA不是Player,那就继续判断nodeB3.如果nodeA和nodeB都不是Player对象,那我们就不做处理,因为怪物和怪物之间的碰撞不需要做处理4.如果找到Player对象,那就判断other对象是不是墙,是的话,那就让Player加1滴血5.由于这个实例缺少很多功能,比如UI、数据绑定、碰撞时产生的动画效果之类的,所以没法直观地看到Player加血的动作,只好用打印日志的方式来查看了。 有朋友提醒我漏了讲解Player的beAtked函数,这里补充一下,如代码:
void Player::beAtked(int iValue) { if (iValue < 0) { cure(-iValue); } else { hurt(std::abs(iValue)); } } void Player::hurt(int iValue) { setiHP(getiHP() - iValue); } void Player::cure(int iValue) { setiHP(getiHP() + iValue); }
好了,现在用调试模式运行游戏(键盘F5),使劲让主角撞墙吧,然后看看日志输出:player cur HP:101player cur HP:102player cur HP:103player cur HP:104player cur HP:105player cur HP:106player cur HP:107player cur HP:108player cur HP:109 如果有类似以上的日志输出,那就证明我们成功了~
相关文章推荐
- Cocos2d-x3.0游戏实例之《别救我》第七篇——物理世界的碰撞检測
- Cocos2d-x3.0游戏实例之《别救我》第二篇——创建物理世界
- Cocos2d-x3.0游戏实例之《别救我》第二篇——创建物理世界
- Cocos2d-x3.0游戏实例之《别救我》第二篇——创建物理世界
- cocos2d-x 3.0游戏实例学习笔记 《跑酷》第七步--物理碰撞检测(1)
- cocos2d-x 3.0游戏实例学习笔记 《跑酷》第七步--物理碰撞检测(2)--主角吃金币
- Cocos2d-x3.0游戏实例之《别救我》第三篇——循环滚动背景(上)
- Cocos2d-x3.0游戏实例之《别救我》第三篇——循环滚动背景(下)
- 实例介绍Cocos2d-x物理引擎:碰撞检测
- 实例介绍Cocos2d-x物理引擎:碰撞检测
- Cocos2d-x3.0游戏实例之《别救我》第五篇——使用Cocostudio UI编辑器创建操作界面
- 实例介绍Cocos2d-x物理引擎:碰撞检测
- Cocos2d-x 3.2 lua飞机大战开发实例(三)道具的掉落,碰撞检测,声音,分数,爆炸效果,完善游戏的功能细节
- Cocos2d-x3.0游戏实例之《别救我》第八篇——TiledMap实现关卡编辑器
- cocos2d-x 3.0游戏实例学习笔记 《跑酷》第七步--物理碰撞检測(1)
- Cocos2d-x3.0游戏实例《别救我》目录
- Cocos2d-x3.0游戏实例之《别救我》第九篇——从tmx文件中加载关卡怪物
- 学习 "使用cocos2d-x3.0和物理引擎实现碰撞检测" 中出现的一个问题
- Cocos2d-x3.0游戏实例之《别救我》第六篇——从代码中获取UI控件
- Cocos2d-x3.0游戏实例之《别救我》第六篇——从代码中获取UI控件