~~~~我的生活,我的点点滴滴!!
相信下面的这个图片大家一定不陌生,我们就以此为基础来继续说cocos2dx中box2d的使用,下面这个游戏中用到Box2D的地方有哪些了?
白色圆壶与红色圆壶碰撞及红色圆壶与四周的碰撞等都是的。
的外表由sprite表现,但是他的内心由Box2D来操控。
//b2Sprite.h
class b2Sprite : public Sprite { public: b2Sprite(GameLayer *game, int type); CC_SYNTHESIZE(b2Body*, _body, Body); CC_SYNTHESIZE(GameLayer*, _game, Game); CC_SYNTHESIZE(int, _type, Type); virtual void setSpritePosition(Point position); virtual void update(float dt); virtual void hide(void); virtual void reset(void); virtual float mag(); };
//当你为一个精灵设置位置和旋转角度的时候,会同样改变它的b2Body的位置和旋转角度 void b2Sprite::setSpritePosition(Point position) { setPosition(position); if(_body) { _body->SetTransform(b2Vec2( position.x / PTM_RATIO, position.y / PTM_RATIO), _body->GetAngle()); } } //当精灵的b2Body根据碰撞发生位置上的偏移时,会改变它的精灵的位置和旋转角度 void b2Sprite::update(float dt) { if(_body && isVisible()) { setPositionX(_body->GetPosition().x * PTM_RATIO); setPositionY(_body->GetPosition().y * PTM_RATIO); setRotation(CC_RADIANS_TO_DEGREES(-1 * _body->GetAngle())); } }
class Player : public b2Sprite { PlayerState m_state; public: CC_SYNTHESIZE(CCPoint,_nextPosition,NextPosition); Player(GameLayer *game,int type, Point position); virtual ~Player(void); Rect rect(); float radius(); bool containsTouchLocation(Touch* touch); static Player* create(GameLayer *game,int type, Point position); virtual bool onTouchBegan(Touch* touch, Event* event); virtual void onTouchMoved(Touch* touch, Event* event); virtual void onTouchEnded(Touch* touch, Event* event); virtual void update(float dt); virtual void reset(); private: void initPlayer(); Point _startPosition; };
一下不知道是不是只能在主场景中使用触摸。下面是initPlayer()函数中完成刚体绑定:
//初始化玩家 void Player::initPlayer() { m_state = kPlayerStateUngrabbed; this->initWithFile("mallet.png"); b2BodyDef bodyDef; //玩家肯定是动态物体,他需要运动,并且还要有碰撞 bodyDef.type = b2_dynamicBody; //_body在父类b2Sprite中定义,继承过来 _body = _game->getWorld()->CreateBody(&bodyDef); _body->SetSleepingAllowed(true); //设置物体的线性阻尼 _body->SetLinearDamping(1.2); //设置物体角阻尼 _body->SetAngularDamping(0.8); b2CircleShape circle; circle.m_radius = radius() / PTM_RATIO; b2FixtureDef fixtureDef; fixtureDef.shape = &circle; fixtureDef.density = 10; fixtureDef.restitution = 1; //fixtureDef.filter.maskBits = 0x0100; _body->CreateFixture(&fixtureDef); //绑定刚体与精灵对象 _body->SetUserData(this); setSpritePosition(_nextPosition); //开启触摸 auto touchListener = EventListenerTouchOneByOne::create(); touchListener->onTouchBegan = CC_CALLBACK_2(Player::onTouchBegan, this); touchListener->onTouchMoved = CC_CALLBACK_2(Player::onTouchMoved, this); touchListener->onTouchEnded = CC_CALLBACK_2(Player::onTouchEnded, this); Director::getInstance()->getEventDispatcher()->addEventListenerWithSceneGraphPriority(touchListener, this); }
//Ball.h class Ball : public b2Sprite { public: Ball(GameLayer *game,int type, Point position); ~Ball(void); static Ball* create(GameLayer *game, int type, Point position); virtual void reset(void); virtual void update(float dt); float radius(); private: void initBall(); Point _startPosition; };
//初始化ball void Ball::initBall() { this->initWithFile("puck.png"); b2BodyDef bodyDef; bodyDef.type = b2_dynamicBody; _body = _game->getWorld()->CreateBody(&bodyDef); _body->SetSleepingAllowed(true); _body->SetLinearDamping(1.2); _body->SetAngularDamping(0.8); b2CircleShape circle; circle.m_radius = radius() / PTM_RATIO; b2FixtureDef fixtureDef; fixtureDef.shape = &circle; fixtureDef.density = 5; fixtureDef.restitution = 0.7; //fixtureDef.filter.categoryBits = 0x0100; _body->CreateFixture(&fixtureDef); _body->SetUserData(this); setSpritePosition(_startPosition); }
能穿过球门,但是要能及时监听到球进来了,这样就需要设置isSensor=true;
//Goal.h class Goal : public b2Sprite { public: Goal(GameLayer *game,int type,Point position); ~Goal(); static Goal* create(GameLayer *game, int type,Point position); void reset(); private: void initGoal(); CCPoint _startPosition; };
//初始化球门 void Goal::initGoal() { this->initWithFile("tansparent.png"); b2BodyDef bodyDef; bodyDef.type = b2_dynamicBody; _body = _game->getWorld()->CreateBody(&bodyDef); //球门定义为一个四边形 b2PolygonShape polygon; polygon.SetAsBox(GOAL_WIDTH / 2 / PTM_RATIO,10 / PTM_RATIO); b2FixtureDef fixtureDef; fixtureDef.shape = &polygon; //不参加碰撞,但是要监听碰撞事件,所以要把isSensor设置成true fixtureDef.isSensor = true; _body->CreateFixture(&fixtureDef); _body->SetUserData(this); setSpritePosition(_startPosition); }
#include "Box2D/Box2D.h" //依然需要继承b2ContactListener class CollisionListener : public b2ContactListener { public: virtual void BeginContact(b2Contact* contact); //virtual void PreSolve(b2Contact* contact, const b2Manifold* oldManifold); };
void CollisionListener::BeginContact(b2Contact* contact) { b2Body *bodyA = contact->GetFixtureA()->GetBody(); b2Body *bodyB = contact->GetFixtureB()->GetBody(); b2Sprite *spriteA = (b2Sprite *)bodyA->GetUserData(); b2Sprite *spriteB = (b2Sprite *)bodyB->GetUserData(); if(spriteA && spriteB) { if(spriteA->getType() == kGoalTop && spriteB->getType() == kBall) { spriteB->getGame()->setScore(kPlayer1GetScore); } else if(spriteB->getType() == kGoalTop && spriteA->getType() == kBall) { spriteB->getGame()->setScore(kPlayer1GetScore); } else if(spriteA->getType() == kGoalBottom && spriteB->getType() == kBall) { spriteB->getGame()->setScore(kPlayer2GetScore); } else if(spriteB->getType() == kGoalBottom && spriteA->getType() == kBall) { spriteB->getGame()->setScore(kPlayer2GetScore); } } }
码,代码中会有注释,看完就一目了然了。
//初始化场景中物理世界 void GameLayer::initPhysics() { b2Vec2 gravity; //我们是在一个平面上,所以只需要将重力加速度设置为0 gravity.Set(0.0f, 0.0f); _world = new b2World(gravity); _world->SetAllowSleeping(true); _world->SetContinuousPhysics(true); //b2ContactListener,这里可以自定义处理物体碰撞发生的事情 //比如球碰到球门,我们希望重置游戏。 _collisionListener = new CollisionListener(); _world->SetContactListener(_collisionListener); //显示轮廓 m_debugDraw = new GLESDebugDraw(PTM_RATIO); _world->SetDebugDraw(m_debugDraw); uint32 flags = 0; flags += b2Draw::e_shapeBit; m_debugDraw->SetFlags(flags); //玩家1 Point player1Position = Point(_screenSize.width * 0.5, 80); _player1 =(Player*) Player::create(this, kPlayer1Tag, player1Position); this->addChild(_player1, 0, kPlayer1Tag); //玩家2 Point player2Position = Point(_screenSize.width * 0.5, _screenSize.height - 80); _player2 =(Player*) Player::create(this, kPlayer2Tag, player2Position); this->addChild(_player2, 0, kPlayer2Tag); //红色圆壶 Point ballPosition = Point(_screenSize.width * 0.5, _screenSize.height * 2 / 5); _ball = Ball::create(this, kBall, ballPosition); this->addChild(_ball); //玩家1的球门 Point goalTopPosition = Point(_screenSize.width * 0.5, _screenSize.height + _ball->radius() * 2); _goalTop = Goal::create(this, kGoalTop, goalTopPosition); this->addChild(_goalTop); //玩家2的球门 Point goalBottomPosition = Point(_screenSize.width * 0.5,0 - _ball->radius() * 2); _goalBottom = Goal::create(this, kGoalBottom, goalBottomPosition); this->addChild(_goalBottom); //设置四周的边框 b2BodyDef tableBodyDef; tableBodyDef.position.Set(0, 0); b2Body *tableBody = _world->CreateBody(&tableBodyDef); b2EdgeShape tableBox; //bottom tableBox.Set(b2Vec2(0.0f, 0.0f), b2Vec2((_screenSize.width / 2 - GOAL_WIDTH / 2) / PTM_RATIO,0.0f)); tableBody->CreateFixture(&tableBox, 0); tableBox.Set(b2Vec2((_screenSize.width - (_screenSize.width / 2 - GOAL_WIDTH / 2)) / PTM_RATIO, 0.0f), b2Vec2(_screenSize.width / PTM_RATIO,0.0f)); tableBody->CreateFixture(&tableBox, 0); //top tableBox.Set(b2Vec2(0.0f , _screenSize.height / PTM_RATIO), b2Vec2((_screenSize.width / 2 - GOAL_WIDTH / 2) / PTM_RATIO, _screenSize.height / PTM_RATIO)); tableBody->CreateFixture(&tableBox,0); tableBox.Set(b2Vec2((_screenSize.width - (_screenSize.width / 2 - GOAL_WIDTH / 2)) / PTM_RATIO , _screenSize.height / PTM_RATIO), b2Vec2(_screenSize.width / PTM_RATIO, _screenSize.height / PTM_RATIO)); tableBody->CreateFixture(&tableBox,0); //left tableBox.Set(b2Vec2(0.0f, 0.0f),b2Vec2(0.0f,_screenSize.height / PTM_RATIO)); tableBody->CreateFixture(&tableBox,0); //right tableBox.Set(b2Vec2(_screenSize.width / PTM_RATIO, 0.0f), b2Vec2(_screenSize.width / PTM_RATIO, _screenSize.height / PTM_RATIO)); tableBody->CreateFixture(&tableBox, 0); // }
void GameLayer::update(float delta) { //调用Box2D的刷新函数 _world->Step(delta, 10, 10); //调用各个对象的update()函数 _ball->update(delta); _player1->update(delta); _player2->update(delta); if(getScore() == kPlayer1GetScore) { this->playerScore(1); setScore(kNoneGetScore); } else if(getScore() == kPlayer2GetScore) { this->playerScore(2); setScore(kNoneGetScore); } }
或者看cocos2dx的官方例子cpp-test里面也有好多复杂的例子,并且我自己也不太懂,等以后做项目时运用到在去学吧。后续开始opengles的学习
了,他将和box2d交叉学习,因为box2d里面的绘图也是用的opengles。