转载:http://blog.csdn.net/u012945598/article/details/17787243
Box2dHandler.h
#include "cocos2d.h"
#include "Box2D.h"
#include "GLES-Render.h"
USING_NS_CC;
#define PTM_RATIO 32
class B2Sprite :public CCSprite
{
public:
// static B2Sprite *spriteWithSpriteFrameName(const char*file);
// bool initWithSpriteFrameName(const char *pszSpriteFrameName);
// 物理世界的“物体”
CC_SYNTHESIZE(b2Body*, m_b2Body, B2Body);
// 是否死去
// IsDead为true,表示彻底从屏幕上消失
CC_SYNTHESIZE(bool, m_isDead, IsDead);
// 是否存活
// IsAlive为true,则物体存活,代表仍然存在碰撞体积,需要考虑碰撞
CC_SYNTHESIZE(bool, m_isAlive, IsAlive);
};
class Box2dHandler:public CCNode,public b2ContactListener
{
public:
// 用于调试绘图
GLESDebugDraw *m_debugDraw;
// 物理世界
b2World *m_world;
// 用于保存死亡对象对容器
// typedef pair<b2Fixture *, b2Fixture *> MyContact;
// set<MyContact> m_contacts;
// 初始化物理世界
bool initBox2D();
// 设置物体 密度为10
void addBodyForSprite(B2Sprite *sprite,double density=10.0);
// 设置夹具 密度为10
void addFixtureForSprite(B2Sprite *sprite,double density=10.0);
//此方法用于销毁死亡对象,因为物体不可以则碰撞检测方法中直接销毁,可以中updata函数最后执行
void dealCollisions();
// 碰撞检测方法 开始重叠
virtual void BeginContact(b2Contact *contact);
// 结束重叠
virtual void EndContact(b2Contact *contact);
// 对应碰撞处理对前后时间点
// virtual void ProSolve(b2Contact *contact,const b2Manifold *oldManifold);
// virtual void PostSolve(b2Contact *contact,const b2ContactImpulse *impulse);
static Box2dHandler* handler();
bool init();
void draw();
void update(float dt);
// void removeSprite(B2Sprite *node);
// CC_SYNTHESIZE(Box2dHandlerDe, , )
};
Box2dHandler.cpp
#include "Box2dHandler.h"
//把Box2dHandler设置成单例
Box2dHandler* Box2dHandler::handler()
{
static Box2dHandler *handler=NULL;
if(handler==NULL)
{
handler=new Box2dHandler();
handler->init();
return handler;
}
else
return handler;
}
//Box2dHandler初始化
bool Box2dHandler::init()
{
this->initBox2D();
this->scheduleUpdate();
// GLESDebugDraw m_debugDraw(PTM_RATIO);
// 调试绘图
m_debugDraw=new GLESDebugDraw(PTM_RATIO);
uint32 flags=0;
flags+=b2Draw::e_shapeBit;
m_debugDraw->SetFlags(flags);
m_world->SetDebugDraw(m_debugDraw);
return true;
}
//初始化物理引擎
bool Box2dHandler::initBox2D()
{
CCSize s=CCDirector::sharedDirector()->getWinSize();
// 设置物理世界中的重力xy。
b2Vec2 gravity;
gravity.Set(0.0f, -1.0f);
m_world=new b2World(gravity);
// 允许睡眠,可以提高物体的处理效率,只有中受到物理效果影响时才会唤醒对象
m_world->SetAllowSleeping(true);
// 开启连续物理测试
// 连续物理测试会使物理模拟时间间隔缩短,提高模拟精度,避免速度较快的两个物体直接穿透
// 但该方法同样会降低引擎但运行性能
m_world->SetContinuousPhysics(true);
// 设置碰撞事件的监听器
m_world->SetContactListener(this);
// 定义一个边界范围,存在碰撞效果
b2BodyDef groundBodyDef;
groundBodyDef.position.Set(0, 0);
b2Body *groundBody=m_world->CreateBody(&groundBodyDef);
// 定义边缘形状
b2EdgeShape groundBox;
// 底部
groundBox.Set(b2Vec2(0,0), b2Vec2(s.width/PTM_RATIO,0));
groundBody->CreateFixture(&groundBox,0);
// 顶部
groundBox.Set(b2Vec2(0,s.height/PTM_RATIO), b2Vec2(s.width/PTM_RATIO,s.height/PTM_RATIO));
groundBody->CreateFixture(&groundBox,0);
// 左侧
groundBox.Set(b2Vec2(0,s.height/PTM_RATIO), b2Vec2(0,0));
groundBody->CreateFixture(&groundBox,0);
// 右侧
groundBox.Set(b2Vec2(s.width/PTM_RATIO,s.height/PTM_RATIO), b2Vec2(s.width/PTM_RATIO,0));
groundBody->CreateFixture(&groundBox,0);
return true;
}
//为物理世界但精灵添加夹具
void Box2dHandler::addFixtureForSprite(B2Sprite *sprite,double density)
{
// 定义形状,多边形
b2PolygonShape spriteShape;
// 得到精灵的大小
CCSize size =sprite->getContentSize();
spriteShape.SetAsBox(size.width/PTM_RATIO/2, size.height/PTM_RATIO/2);
// 创建一个夹具的对象
b2FixtureDef spriteShapeDef;
// 设置夹具的形状
spriteShapeDef.shape=&spriteShape;
// 设置夹具的密度
spriteShapeDef.density=density;
// 设置精灵物理世界的“物体”的夹具
b2Body *spriteBody=sprite->getB2Body();
spriteBody->CreateFixture(&spriteShapeDef);
}
//为物理世界的精灵创建Box2D物体
void Box2dHandler::addBodyForSprite(B2Sprite *sprite,double density)
{
// 创建一个物体对象
b2BodyDef spriteBodyDef;
// 物体对象--b2Body
// 静态物体(b2_staticBody)。质量为 0,不可以移动,通常模拟我们游戏的物理边
// 界:大地、墙壁等。
// 平台物体(b2_kinematicBody)。按照固定路线运动的物体,比如说电梯,运动的
// 滚梯,运行的火车等等。
// 动态物体(b2_dynamicBody)。我们最常见的精灵对象对应的物体。
// 物体类型为动态物体
spriteBodyDef.type=b2_dynamicBody;
spriteBodyDef.position.Set((sprite->getPosition().x)/PTM_RATIO, (sprite->getPosition().y)/PTM_RATIO);
// 设置用户数据,允许存放一个任意类型的指针向我们自定义的数据
// 用于将物体与游戏程序关联起来,所有物体的用完数据应指向相同的数据类型
spriteBodyDef.userData=sprite;
// 在物理世界中创建物体
b2Body *spriteBody=m_world->CreateBody(&spriteBodyDef);
// 为精灵添加物体
sprite->setB2Body(spriteBody);
// 为精灵添加夹具
this->addFixtureForSprite(sprite,density);
}
// 更新状态
void Box2dHandler::update(float dt)
{
// 遍历物理世界中的物体
for(b2Body *b=m_world->GetBodyList();b;b=b->GetNext())
{
// 是否没有精灵数据
if(b->GetUserData()!=NULL)
{
B2Sprite *sprite =static_cast<B2Sprite*>(b->GetUserData());
// b2Vec2 pos=b->GetPosition();
// b2Vec2 bPosition=b2Vec2(pos.x+sprite->getPosition().x/PTM_RATIO,pos.y+sprite->getPosition().y/PTM_RATIO);
// sprite->setPosition(ccp(pos.x*PTM_RATIO+sprite->getPosition().x,pos.y*PTM_RATIO+sprite->getPosition().y));
// float32 bAngle=-CC_DEGREES_TO_RADIANS(sprite->getRotation());
// b->SetTransform(bPosition, bAngle);
// // sprite->setRotation(-b->GetAngle()/0.01745329252f);
sprite->setPosition(ccp(b->GetPosition().x*PTM_RATIO,b->GetPosition().y*PTM_RATIO));
sprite->setRotation(-CC_RADIANS_TO_DEGREES(b->GetAngle()));
}
}
// Box世界的刷新接口,第一个参数为更新引擎的间隔时间,第二个参数为计算速度,第三个参数为位置时迭代的次数
m_world->Step(dt, 8, 8);
//this->dealCollisions();
}
//使调试绘图显示到屏幕上
void Box2dHandler::draw()
{
CCNode::draw();
// 保存opengl绘图状态
ccGLEnableVertexAttribs(kCCVertexAttribFlag_Position);
// 用kmGLPushMatrix函数来保存状态
kmGLPushMatrix();
// 绘制调试图案
m_world->DrawDebugData();
// 用kmGLPopMatrix函数来恢复状态
kmGLPopMatrix();
}
void Box2dHandler::BeginContact(b2Contact *contact)
{
printf("开始碰撞");
}
void Box2dHandler::EndContact(b2Contact *contact)
{
printf("结束碰撞");
}
测试代码:
// 获取可视区域大小
CCSize visibleSize = CCDirector::sharedDirector()->getVisibleSize();
// 获取可视区域左下角坐标
CCPoint origin = CCDirector::sharedDirector()->getVisibleOrigin();
// 创建物理世界
Box2dHandler *handler =Box2dHandler::handler();
this->addChild(handler);
B2Sprite* pSprite =new B2Sprite();
pSprite->initWithFile("CloseNormal.png");
pSprite->setPosition(ccp(visibleSize.width/2 + origin.x, visibleSize.height/1.1 + origin.y));
handler->addBodyForSprite(pSprite);
B2Sprite* pSprite2 =new B2Sprite();
pSprite2->initWithFile("CloseNormal.png");
pSprite2->setPosition(ccp(visibleSize.width/2 + origin.x, visibleSize.height/6 + origin.y));
handler->addBodyForSprite(pSprite2);
this->addChild(pSprite);
this->addChild(pSprite2);