让子弹飞是我很喜欢的一款游戏。今天的目标就是利用cocos2dx 3.0 和box2d 打造一款这种类型游戏的Demo版。本来cocos2dx 3.0 已经封装了physicals模块,但是我在使用的过程中遇到了一些问题,比如子弹速度过快时候会出屏等,所以就觉得还是直接封装box2d API来完成这款Demo。
我主要封装了两个类,一个叫Box2dHandler, 这个类继承自Node和b2ContactListener, 是用来和box2d打交道的。可以用来创建方形,圆形的静态或者动态刚体。创建物理世界,以及处理碰撞的检测重任都交给这个类了。另外一个类叫B2Sprite, 也继承自Node,本来是想继承自Sprite的,但是在实现过程中发现有问题。就改成继承自Node。它的功能是用来粘合cocos2dx和Box2D, 起到一个中间的桥梁作用。这里要感谢一下<<cocos2d-x高级开发教程>>一书,这两个类基本从它移植而来,但是原书使用的是2.0版本。所以还是要做一些修改。
好了,闲话到此为止。上代码。
首先是Box2dHandler。
#ifndef __BOX2DHANDLER_H__
#define __BOX2DHANDLER_H__
#include "cocos2d.h"
#include "Box2D.h"
#include "Box2dHandlerDelegate.h"
#include "B2Sprite.h"
USING_NS_CC;
enum shape
{
box=1,
circle=2,
};
class Box2dHandler : public cocos2d::Node, public b2ContactListener
{
private:
b2World *m_world;
typedef std::pair<b2Fixture*, b2Fixture*> MyContact;
std::set<MyContact> m_contacts;
public:
bool init();
bool initBox2D();
void addBodyForSprite(B2Sprite* sprite, double density = 1.0, double friction = 0.9, double restituion = 0.1, shape type=box);
void addFixtureForSprite(B2Sprite* sprite, double density = 1.0, double friction = 0.9, double restituion = 0.1, shape type=box);
void addStaticBodyForSprite(B2Sprite* sprite, double density = 0.0);
void dealCollision();
public:
virtual void BeginContact(b2Contact * contact);
virtual void EndContact(b2Contact * contact);
static Box2dHandler * handler();
//void draw();
void update(float dt);
CC_SYNTHESIZE(Box2dHandlerDelegate*, m_delegate, Delegate);
};
#endif // __BOX2DHANDLER_H__
熟悉box2d的话,很容易看清楚这个类就是封装了基本的Box2D操作。包括创建刚体,以及监听碰撞。
接下来是实现代码。
#include "Box2dHandler.h"
#include "HelloWorldScene.h"
#define PTM_RATIO 32
Box2dHandler * Box2dHandler::handler()
{
static Box2dHandler * handler = NULL;
if(handler == NULL)
{
handler = new Box2dHandler();
handler->init();
return handler;
}
else
{
return handler;
}
}
bool Box2dHandler::init()
{
this->initBox2D();
this->scheduleUpdate();
return true;
}
bool Box2dHandler::initBox2D()
{
Size s = Director::getInstance()->getWinSize();
b2Vec2 gravity;
gravity.Set(0.0f, -10.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;
//Bottom
//groundBox.Set(b2Vec2(0, 0), b2Vec2(s.width/PTM_RATIO, 0));
//groundBody->CreateFixture(&groundBox, 0);
//Top
groundBox.Set(b2Vec2(0, s.height/PTM_RATIO), b2Vec2(s.width/PTM_RATIO, s.height/PTM_RATIO));
groundBody->CreateFixture(&groundBox, 0);
//Left
groundBox.Set(b2Vec2(0, s.height/PTM_RATIO), b2Vec2(0,0));
groundBody->CreateFixture(&groundBox, 0);
//Right
groundBox.Set(b2Vec2(s.width/PTM_RATIO, s.height/PTM_RATIO), b2Vec2(s.width/PTM_RATIO, 0));
gro