cocos2dx box2d使用(一)

本例子使用的是cocos2d-x 3.0版本
  1. 首先創建一個cocos2d的c++工程,這裏就不多做說明了!本例子的項目名稱是MyGame
  2. 其次,在MyGame的工程設置裏Build Settings下,把CC_ENABLE_CHIPMUNK_INTEGRATION=1改爲CC_ENABLE_BOX2D_INTEGRATION=1,同樣把項目所引入的cocos2d的工程裏改一下,但cocos2d的工程修改的地方有點特別!
    screenshot.png
    如上圖的工程,非target!
  3. 到此,box2d的環境已經設定好了!
現在工程已經創建完成了,環境也設定好了,下代碼工程:
screenshot.png
創建一個layer,用於放置所有的box2d對像和項目的精靈
其中的頭文件如下:
//
//  Box2dTest.h
//  MyGame
//
//  Created by Poche on 5/17/14.
//
//

#ifndef __MyGame__Box2dTest__
#define __MyGame__Box2dTest__

#include "cocos2d.h"
#include
 "Box2D/Box2D.h"

class Box2dTest : public cocos2d::Layer {
public:
    Box2dTest();
   
 virtual ~Box2dTest();
   
 CREATE_FUNC(Box2dTest);
   
   
 /**
     *@brief
初始化box2d測試layerbox2d世界是獨立於cocosscene
     *
     *@Modified by poche at 2014-05-18 18:00:17
     *
     *@return
是否初始化成功
    **/

   
 bool init();
   
 /**
     *@brief
初始化box2d世界
     *
     *@Modified by poche at 2014-05-18 18:01:43
    **/

   
 void initWorld();
private:
   
 b2World *m_world;   /// box2d世界
   
 /// layer上的點擊加調
   
 CC_SYNTHESIZE_RETAIN(cocos2d::EventListenerTouchAllAtOnce*, m_touchListener,_touchListener);
public:
   
 /**
     *@brief
添加精靈到指定座標
     *
     *@Modified by poche at 2014-05-18 18:02:44
     *@param point
 座標
    **/

   
 void AddSprite(cocos2d::Point point);
   
 /**
     *@brief
每幀檢查box2d物體並且更新cocos的精靈的狀態(位置等)
     *
     *@Modified by poche at 2014-05-18 18:03:25
     *@param dt
 時間間隔
    **/

   
 void update(float dt);
   
 /**
     *@brief
添加點擊回調事件
     *
     *@Modified by poche at 2014-05-18 18:04:39
    **/

   
 void addLayerTouchListener();
   
 /**
     *@brief
點擊結束後的加調方法
     *
     *@Modified by poche at 2014-05-18 18:04:56
     *@param touches
 點擊集合
     *@param event
 事件類型
    **/

   
 void touchesEnd(const std::vector<cocos2d::Touch*> touches, cocos2d::Event *event);
   
 virtual void onExit();
};

#endif /* defined(__MyGame__Box2dTest__) */

下面看一下.cpp的代碼:
//
//  Box2dTest.cpp
//  MyGame
//
//  Created by Poche on 5/17/14.
//
//

#include "Box2dTest.h"
USING_NS_CC
;

/// box2d裏,其用到的單位是現實中的單位,米等
/// 所以在遊戲裏,我們需要作出轉換
/// cocos2d裏,每32個像素就相當box2d裏的一米
#define PTM_RATIO 32

const int tagSprite = 1;

Box2dTest::Box2dTest()
:
 m_touchListener(NULL)
{
   
}

Box2dTest::~Box2dTest() {
   
 CC_SAFE_RELEASE(m_touchListener);
   
 /// 記得移除對像,要不然會泄露
   
 delete m_world;
   
 m_world = NULL;
}

bool Box2dTest::init() {
   
 /// 添加點擊響應
   
 addLayerTouchListener();
   
 /// 初始化世界
   
 initWorld();
   
 return true;
}
void Box2dTest::initWorld() {
   
   
 auto size = Director::getInstance()->getWinSize();
   
 /// 設置box2d世界重力方向
   
 b2Vec2 gravity(0.0f, -10.0f);
   
 bool doSleep    = true;
   
   
 /// 生成box2d世界
   
 m_world = new b2World(gravity);
   
 /// 是否允許睡眠
   
 m_world->SetAllowSleeping(doSleep);
   
 m_world->SetContinuousPhysics(true);
   
   
 /// 地表物體定義
   
 b2BodyDef groundBodyDef;
   
 /// 通過地表物體定義生成地表物體
   
 b2Body* groundBody  = m_world->CreateBody(&groundBodyDef);
   
 /// 形狀
   
 b2PolygonShape groundBox;
   
   
 /// 作爲box形態佈局
   
 /// 第一個參數  物體的寬
   
 /// 第二個參數  物體的高
   
 /// 第三個參數  物體的位置
   
 /// 第四個參數  物體中角度
   
 /// 牆底
    groundBox.
SetAsBox(size.width / PTM_RATIO, 0, b2Vec2(0, 0), 0);
   
 /// 把已經生成的物體放入世界中
   
 /// 第一個參數  要放入的物體
   
 /// 第二個參數  物體的質量
    groundBody->
CreateFixture(&groundBox, 0);
   
 /// 牆頂
    groundBox.
SetAsBox(size.width / PTM_RATIO, 0, b2Vec2(0, size.height / PTM_RATIO), 0);
    groundBody->
CreateFixture(&groundBox, 0);
   
 /// 左牆
    groundBox.
SetAsBox(0, size.height / PTM_RATIO, b2Vec2(0, 0), 0);
    groundBody->
CreateFixture(&groundBox, 0);
   
 /// 左牆
    groundBox.
SetAsBox(0, size.height / PTM_RATIO, b2Vec2(size.width / PTM_RATIO, 0), 0);
    groundBody->
CreateFixture(&groundBox, 0);
   
   
 /// cocos2d裏的精靈
   
 auto brick  = SpriteBatchNode::create("CloseNormal.png");
   
 addChild(brick, 2, tagSprite);
   
   
 /// 每幀對cocos2d的精靈更新
   
 schedule(schedule_selector(Box2dTest::update));
}

void Box2dTest::AddSprite(cocos2d::Point point) {
   
 auto batch = (SpriteBatchNode*)getChildByTag(tagSprite);
   
   
 auto sprite = Sprite::createWithTexture(batch->getTexture(), Rect(0,0,32,32));
    batch->
addChild(sprite);
   
    sprite->
setPosition(Point(point.x, point.y));
   
   
 /// 創建動態物體
   
 /// 物體定義
   
 b2BodyDef bodyDef;
   
 /// 物體爲動態物體
    bodyDef.
type = b2_dynamicBody;
   
 /// 物體的位置
    bodyDef.
position.Set(point.x / PTM_RATIO, point.y/ PTM_RATIO);
   
 /// 將已經生成的精靈捆綁到物體上
    bodyDef.
userData = sprite;
   
 /// 創建物體
   
 b2Body * body = m_world->CreateBody(&bodyDef);
   
   
 b2PolygonShape dynamicBox;
    dynamicBox.
SetAsBox(0.5f, 0.5f);
   
   
 b2FixtureDef fixtureDef;
    fixtureDef.
shape = &dynamicBox;
   
 /// 設置摩擦係數
    fixtureDef.
friction = 0.3f;
   
 /// 設置密度
    fixtureDef.
density = 1.0;
    body->
CreateFixture(&fixtureDef);
}

void Box2dTest::update(float dt) {
   
 int velocityIterations = 8;
   
 int positionIterations = 1;
   
   
 //每次遊戲循環你都應該調用b2World::Step
   
 m_world->Step(dt, velocityIterations, positionIterations);
   
   
   
 for(b2Body* b = m_world->GetBodyList(); b; b = b->GetNext())
    {
       
 if(b->GetUserData() != NULL)
        {
           
 /// 更新cocos2d對像
           
 auto sprite = (Sprite*)b->GetUserData();
            sprite->
setPosition(Point(b->GetPosition().x * PTM_RATIO, b->GetPosition().y * PTM_RATIO));
            sprite->
setRotation( -1 * CC_RADIANS_TO_DEGREES(b->GetAngle()) );
        }
    }
}

void Box2dTest::addLayerTouchListener() {
   
 set_touchListener(EventListenerTouchAllAtOnce::create());
   
 get_touchListener()->onTouchesEnded = CC_CALLBACK_2(Box2dTest::touchesEnd, this);
   
 _eventDispatcher->addEventListenerWithSceneGraphPriority(get_touchListener(), this);
   
}

void Box2dTest::onExit() {
   
 Layer::onExit();
   
 unschedule(schedule_selector(Box2dTest::update));
   
 _eventDispatcher->removeEventListener(get_touchListener());
}

void Box2dTest::touchesEnd(const std::vector<cocos2d::Touch *> touches, cocos2d::Event *event) {

   
 for (auto& touch : touches)
    {
       
 auto location = touch->getLocationInView();
        location =
 Director::getInstance()->convertToGL(location);
       
       
 AddSprite(location);
    }
}


解釋:
在這裏要說說box2d中的單位,由於box2d中使用的是米作爲長度單位。但在編程中,我們使用的圖片都是使用像素作爲基本單位。
凡是要向世界對象中添加物體的,都需要將像素單位轉化爲米單位。凡是要將世界對象中的物體顯示在屏幕上時,要將物體的米單位轉化爲像素單位,在cocos2d裏,大多用到的32個像素爲一米,能否改就不得而知了!

SetAsBox 函數接收了半個寬度和半個高度,這樣的話,地面盒就是 100 個單位寬(x 軸)以及 20 個單位高(y 軸)。Box2D 已被調諧使用米,千克和秒來作單位,所以你可以用米來考慮長度。然而, 改變單位系統是可能的。 

發佈了17 篇原創文章 · 獲贊 9 · 訪問量 5萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章