|   版权声明:本文为博主原创文章,未经博主允许不得转载。

在Box2D中碰撞事件由b2ContactListener类函数实现,b2ContactListener是Box2D提供的抽象类,它的抽象函数:

 /// Called when two fixtures begin to touch.两个物体开始接触时会响应,但只调用一次。
virtual void BeginContact(b2Contact* contact) { B2_NOT_USED(contact); } /// Called when two fixtures cease to touch.分离时响应。但只调用一次。
virtual void EndContact(b2Contact* contact) { B2_NOT_USED(contact); } /// This is called after a contact is updated. This allows you to inspect a
/// contact before it goes to the solver. If you are careful, you can modify the
/// contact manifold (e.g. disable contact).
/// A copy of the old manifold is provided so that you can detect changes.
/// Note: this is called only for awake bodies.
/// Note: this is called even when the number of contact points is zero.
/// Note: this is not called for sensors.
/// Note: if you set the number of contact points to zero, you will not
/// get an EndContact callback. However, you may get a BeginContact callback
/// the next step.持续接触时响应,它会被多次调用。
virtual void PreSolve(b2Contact* contact, const b2Manifold* oldManifold)
{
B2_NOT_USED(contact);
B2_NOT_USED(oldManifold);
} /// This lets you inspect a contact after the solver is finished. This is useful
/// for inspecting impulses.
/// Note: the contact manifold does not include time of impact impulses, which can be
/// arbitrarily large if the sub-step is small. Hence the impulse is provided explicitly
/// in a separate data structure.
/// Note: this is only called for contacts that are touching, solid, and awake. /// 持续接触时响应,调用完preSolve后调用。
virtual void PostSolve(b2Contact* contact, const b2ContactImpulse* impulse)
{
B2_NOT_USED(contact);
B2_NOT_USED(impulse);
}

第一步:我们检测碰撞的类要继承自public b2ContactListener

第二步:创建物理世界的监听对象(在init()中添加)

第三步:在类中添加检测碰撞的函数(上面的四个中选择一个)

第四步:进行碰撞检测

如上:我要检测小鸟是否受到了碰撞,那么我通过contact->GetFixtureA()和contact->GetFixtureB()去取得当前的物理世界中产生碰撞的物体是否等于小鸟的刚体变量(birdBody)。如果相等说明产生了碰撞,如果不相等则说明没有碰撞。

摘自:http://www.cocos2d-x.org/wiki/Box2D

To find out when a fixture collides with another fixture in Box2D, we need to register a contact listener. A contact listener is a C++ object that we give Box2D, and it will call methods on that object to let us know when two objects begin to touch and stop touching. we can’t just store references to the contact points that are sent to the listener, because they are reused by Box2D. So we have to store copies of them instead.

void MyContactListener::BeginContact(b2Contact* contact)
{
// We need to copy out the data because the b2Contact passed in
// is reused.
MyContact myContact = { contact->GetFixtureA(), contact->GetFixtureB() };
_contacts.push_back(myContact);
}

The following iterates through all of the buffered contact points, and checks to see if any of them are a match between the ball and the bottom of the screen.

void MyContactListener::EndContact(b2Contact* contact)
{
MyContact myContact = { contact->GetFixtureA(), contact->GetFixtureB() };
std::vector::iterator pos;
pos = std::find(_contacts.begin(), _contacts.end(), myContact);
if (pos != _contacts.end())
{
_contacts.erase(pos);
}
}

In the Helloworld.cpp,“tick” method wil use _contactListener to go through the contact points of bodies that are colliding. If a sprite is intersecting with a block, we add the block to a list of objects to destroy.

b2Body *bodyA = contact.fixtureA->GetBody();
b2Body *bodyB = contact.fixtureB->GetBody();
if (bodyA->GetUserData() != NULL && bodyB->GetUserData() != NULL) {
CCSprite *spriteA = (CCSprite *) bodyA->GetUserData();
CCSprite *spriteB = (CCSprite *) bodyB->GetUserData(); // Sprite A = ball, Sprite B = Block
if (spriteA->getTag() == 1 && spriteB->getTag() == 2) {
if (std::find(toDestroy.begin(), toDestroy.end(), bodyB)
== toDestroy.end()) {
toDestroy.push_back(bodyB);
}
}
// Sprite B = block, Sprite A = ball
else if (spriteA->getTag() == 2 && spriteB->getTag() == 1) {
if (std::find(toDestroy.begin(), toDestroy.end(), bodyA)
== toDestroy.end()) {
toDestroy.push_back(bodyA);
}
}  

Now you have even more techniques to add to Box2D in your game. I look forward to seeing some cool physics games from you guys!

运行代码:

.h files

#ifndef _GAME_PLAY_H_
#define _GAME_PLAY_H_ #define PTM_RATIO 32 #include "cocos2d.h"
#include "Box2D\Box2D.h" USING_NS_CC;
using namespace CocosDenshion; class GamePlay : public cocos2d::Layer, public b2ContactListener
{
private:
cocos2d::Sprite* backgroundA;
cocos2d::Sprite* backgroundB;
cocos2d::Sprite* ready;
cocos2d::Sprite* tutorial;
cocos2d::Sprite* bird;
cocos2d::Sprite* land;
cocos2d::Sprite* num;
cocos2d::Sprite* upPipe;
cocos2d::Sprite* downPipe;
cocos2d::Sprite* pipeContainer;
cocos2d::Sprite* model;
cocos2d::Sprite* gameEnd;
cocos2d::LabelTTF* score;
cocos2d::LabelTTF* best;
cocos2d::MenuItemImage* play;
cocos2d::MenuItemImage* exit;
b2World* world;
b2Body* birdBody;
b2Body* landBody;
b2Body* downBody;
b2Body* upBody;
int bestScore;
int times = 0; private:
void replaceBackground(int);
void tipInformation();
void addBird();
void addLand();
void addPipe(float dt);
void gameBegin(float dt);
void gameOver();
void timeAnimate();
void upperBoundary();
//int birdSelect(float); public:
static cocos2d::Scene* createScene();
virtual bool init();
void initPhysicsWorld();
virtual void update(float); /// Called when two fixtures begin to touch.
virtual void BeginContact(b2Contact* contact); /** Callback function for multiple touches began.
*
* @param touches Touches information.
* @param unused_event Event information.
* @js NA
*/
virtual void onTouchesBegan(const std::vector<Touch*>& touches, Event *unused_event);
void goPlay(cocos2d::Ref* pSender);
void goExit();
CREATE_FUNC(GamePlay);
}; #endif // _GAME_PLAY_H_ .cpp files
#include "GamePlay.h"
#include "GameUnit.h"
#include "GameData.h" unit u3; cocos2d::Scene* GamePlay::createScene()
{
auto scene = Scene::create();
auto layer = GamePlay::create();
scene->addChild(layer);
return scene;
} bool GamePlay::init()
{
if (!Layer::init())
{
return false;
}
this->initPhysicsWorld();
this->replaceBackground(1);
this->tipInformation();
this->upperBoundary();
this->addLand();
this->addBird();
this->timeAnimate(); //设置多点触屏事件的监听器
auto listener = EventListenerTouchAllAtOnce::create();
listener->onTouchesBegan = CC_CALLBACK_2(GamePlay::onTouchesBegan, this);
//注册监听器
_eventDispatcher->addEventListenerWithSceneGraphPriority(listener, this); //设置物理世界监听
world->SetContactListener(this); scheduleOnce(schedule_selector(GamePlay::gameBegin), 3);
//scheduleUpdate(); return true;
} void GamePlay::initPhysicsWorld()
{
//设置重力加速度为9.8;方向向下
b2Vec2 gravity;
gravity.Set(0.0f, -9.8f);
//创建一个新的物理世界
world = new b2World(gravity); //设置是否允许物体休眠
world->SetAllowSleeping(true);
//连续物理测试,防止发生非子弹特性的物体发生穿透现象
world->SetContinuousPhysics(true);
} void GamePlay::replaceBackground(int flag)
{
switch (flag)
{
case 1:
backgroundA = Sprite::create("background/light.png");
backgroundA->setPosition(Vec2(u3.winOrigin().x + u3.winSize().width / 2,
u3.winOrigin().y + u3.winSize().height / 2));
backgroundA->setScale(u3.scaleX(backgroundA, u3.winSize()),
u3.scaleY(backgroundA, u3.winSize()));
this->addChild(backgroundA, 0);
break;
default:
break;
}
} void GamePlay::tipInformation()
{
......
//exit
exit = MenuItemImage::create(
"button/exit_f.png",
"button/exit_b.png",
CC_CALLBACK_0(GamePlay::goExit, this)
);
Menu* menu = Menu::create(exit, NULL);
menu->setPosition(Vec2(u3.winOrigin().x + exit->getContentSize().width / 2,
u3.winOrigin().y + exit->getContentSize().height / 2));
this->addChild(menu, 7);
} void GamePlay::addBird()
{
bird = Sprite::create("bird/littleBird.png");
bird->setPosition(Vec2(u3.winOrigin().x + u3.winSize().width / 3,
u3.winOrigin().y + u3.winSize().height - 5 * (ready->getContentSize().height)));
bird->setScale(1.5);
auto repeat = RepeatForever::create(Animate::create(u3.gameAnimate(1)));
bird->runAction(repeat);
this->addChild(bird, 1); //创建刚体
b2BodyDef birdBodyDef;
birdBodyDef.type = b2_dynamicBody;
birdBodyDef.position.Set(bird->getPosition().x / PTM_RATIO,
bird->getPosition().y / PTM_RATIO);
//将刚体,精灵与世界关联起来
birdBody = world->CreateBody(&birdBodyDef);
birdBody->SetUserData(bird); //定义一个盒子
b2PolygonShape birdBox;
birdBox.SetAsBox(bird->getContentSize().width / 3 / PTM_RATIO,
bird->getContentSize().height / 3 / PTM_RATIO);
//夹具
b2FixtureDef fixtureDef;
//设置夹具的形状
fixtureDef.shape = &birdBox;
birdBody->CreateFixture(&fixtureDef);
} void GamePlay::update(float dt)
{
world->Step(dt, 8, 3);
for (b2Body* bb = world->GetBodyList(); bb; bb = bb->GetNext())
{
if (bb->GetUserData() != nullptr)
{
Sprite* sprite = (Sprite*)bb->GetUserData();
//设置精灵的当前的位置,通过取得精灵的位置乘上相应的像素,这里的PTM_RATIO为32个像素为1m,就可以判断出精灵的位置处于物理世界的何处
sprite->setPosition(Vec2(bb->GetPosition().x*PTM_RATIO,
bb->GetPosition().y*PTM_RATIO));
//设置精灵的角度偏转
sprite->setRotation(0);
}
}
} //添加地面
void GamePlay::addLand()
{
//地板也是物理世界的一个刚体,是一个静态的刚体
land = Sprite::create("background/land.png");
land->setPosition(Vec2(u3.winOrigin().x + u3.winSize().width / 2,
u3.winOrigin().y + land->getContentSize().height / 2));
land->setScaleX(u3.winSize().width / 1.5*land->getContentSize().width);
land->setScaleY(u3.winSize().height / (land->getContentSize().height * 3));
this->addChild(land, 4); //创建刚体
b2BodyDef landBodyDef;
landBodyDef.type = b2_staticBody;
landBodyDef.position.Set(u3.winSize().width / 2 / PTM_RATIO,
land->getPosition().y / PTM_RATIO); landBody = world->CreateBody(&landBodyDef);
landBody->SetUserData(land); b2PolygonShape landShape;
landShape.SetAsBox(u3.winSize().width / 2 / PTM_RATIO,
backgroundA->getContentSize().height / 2 / PTM_RATIO);
//1.4*land->getContentSize().height / PTM_RATIO
b2FixtureDef landFixtureDef;
landFixtureDef.shape = &landShape;
landBody->CreateFixture(&landFixtureDef);
} void GamePlay::upperBoundary()
{
.......
} void GamePlay::addPipe(float dt)
{
times++; float randPipe = -rand() % 3;
//down bar
downPipe = Sprite::create("pipe/down.png");
downPipe->setScaleY(u3.winSize().height / (downPipe->getContentSize().height*1.5));
this->addChild(downPipe, 3);
b2BodyDef downBodyDef;
downBodyDef.position = b2Vec2(u3.winSize().width / PTM_RATIO + 2,
downPipe->getContentSize().height / 2 / PTM_RATIO + randPipe);
// + land->getContentSize().height / PTM_RATIO
downBodyDef.type = b2_kinematicBody;
//修改速度可以提升游戏的难度
downBodyDef.linearVelocity = b2Vec2(-2, 0);
downBody = world->CreateBody(&downBodyDef);
downBody->SetUserData(downPipe);
b2PolygonShape downShape;
downShape.SetAsBox(downPipe->getContentSize().width / 2 / PTM_RATIO,
1.6*downPipe->getContentSize().height / PTM_RATIO);
b2FixtureDef downPipeFixture;
downPipeFixture.shape = &downShape;
downBody->CreateFixture(&downPipeFixture); ......
} void GamePlay::gameOver()
{
//显示Game Over的Logo
.......
//显示奖章牌
...... //奖章
......
//显示成绩
......
//设置字体的颜色为黑色,并将成绩显示在panel面板上
...... unscheduleUpdate();
unschedule(schedule_selector(GamePlay::addPipe));
} void GamePlay::gameBegin(float dt)
{
scheduleUpdate();
//修改时间可以提升游戏的难易程度
schedule(schedule_selector(GamePlay::addPipe), 2);
} void GamePlay::BeginContact(b2Contact* contact)
{
if (contact->GetFixtureA()->GetBody() == birdBody || contact->GetFixtureB()->GetBody() == birdBody)
{
this->gameOver();
}
}

运行截图:

Cocos2d Box2D之碰撞检测的更多相关文章

  1. 如何使用box2d做碰撞检测

    cocos2dx3.0+vs2012编译通过. 主要是通过body->SetTransform来设置body的位置和角度,然后自己写个ContactListener来监听碰撞事件 源代码下载 # ...

  2. Cocos2d Box2D之浮动刚体

    |   版权声明:本文为博主原创文章,未经博主允许不得转载. b2_kinematicBody 运动学物体在模拟环境中根据自身的速度进行移动.运动学物体自身不受力的作用.虽然用户可以手动移动它,但是通 ...

  3. Cocos2d Box2D之静态刚体

    |   版权声明:本文为博主原创文章,未经博主允许不得转载. b2_staticBody 在模拟环境下静态物体是不会移动的,就好像有无限大的质量.在Box2D的内部会将质量至反,存储为零.静态物体也可 ...

  4. Cocos2d Box2D之动态刚体

    |   版权声明:本文为博主原创文章,未经博主允许不得转载. b2_dynamicBody 动态物体可以进行全模拟.用户可以用手手动移动动态刚体,也可以由动态刚体自己受力而自运动.动态物体可以和任何物 ...

  5. Cocos2d Box2D之简介

    |   版权声明:本文为博主原创文章,未经博主允许不得转载. Box2D是一个用于模拟2D刚体物体的C++引擎.Box2D集成了大量的物理力学和运动学的计算,并将物理模拟过程封装到类对象中,将对物体的 ...

  6. 我常用的iphone开发学习网站[原创]

    引用地址:http://www.cnblogs.com/fuleying/archive/2011/08/13/2137032.html Google 翻译 Box2d 托德的Box2D的教程! Bo ...

  7. (转) [it-ebooks]电子书列表

    [it-ebooks]电子书列表   [2014]: Learning Objective-C by Developing iPhone Games || Leverage Xcode and Obj ...

  8. [转]eoe社区cocos2d-x游戏引擎知识大汇总

    [eoeAndroid 社区]特意为大家汇总了cocos2d-x知识贴,分量十足,纯正干或.从基础教程到游戏应用的开发,我们不让知识流失,我们要做知识的搬运工还有加工 师.希望大家能够一起的学习,和大 ...

  9. 《Cocos2d-x实战 工具卷》上线了

    感谢大家一直以来的支持! 各大商店均开始销售:京东:http://item.jd.com/11659696.html当当:http://product.dangdang.com/23659809.ht ...

随机推荐

  1. Codeforces 1093D(染色+组合数学)

    题面 传送门 题目大意:给出一个无向图,每个节点可以填1,2,3三个数中的一个 问有多少种填数方案,使两个相邻节点的数之和为奇数 分析 如果图中有奇环,一定无解 我们对图黑白染色,由于图可能不联通,记 ...

  2. luoguP1966 火柴排队(NOIP2013)(归并排序)

    luogu P1966 火柴排队 题目 #include<iostream> #include<cstdlib> #include<cstdio> #include ...

  3. Linux文件目录可视化远程软件winscp的使用

    这个软件不是必须的,一般有命令行就可以操作文件目录,但winscp有图形界面,双击文件就可以编辑和保存,使用方式更接近windows Winscp是开源软件,安装包可以自行下载获取找有关人士获取 要新 ...

  4. P3452 [POI2007]BIU-Offices(链表+bfs)

    P3452 [POI2007]BIU-Offices 新姿势:链表存图快速删除 显然两个没有直接相连的点要放到同一个集合里 但是直接搞一个图的补图会挂掉 考虑用链表维护点序列 每次bfs删除一个点和与 ...

  5. jxl读取excel浮点数据时,小数点后三位截取问题

    今天导入Excel数据时,发现很多浮点数据被自动四舍五入只保留了三位,原来是jxl里对getContents()进行了封装,对数值型数据作了该处理.一般我们会对读取excel的一整套流程作为工具类,那 ...

  6. C#设计模式:工厂模式

    一,工厂模式 using System; using System.Collections.Generic; using System.Linq; using System.Text; using S ...

  7. hud2243 考研路茫茫——单词情结

    考研路茫茫--单词情结 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Problem ...

  8. node egg | 部署报错:server got error:bind EADDRNOTAVAIL

    egg框架实现的服务,部署在阿里云服务器上报出以下错误: 解决方案: config.js中 exports.cluster = { "listen": { "path&q ...

  9. Maven仓库配置淘宝Maven镜像仓库

    settings.xml文件里面配置 <mirrors> <mirror>       <id>alimaven</id>       <name ...

  10. MySQL中常见函数

    一.日期函数 1.NOW()   返回当前日期和时间 mysql> SELECT NOW(); +---------------------+ | NOW() | +-------------- ...