- 首先創建一個cocos2d的c++工程,這裏就不多做說明了!本例子的項目名稱是MyGame
- 其次,在MyGame的工程設置裏Build Settings下,把CC_ENABLE_CHIPMUNK_INTEGRATION=1改爲CC_ENABLE_BOX2D_INTEGRATION=1,同樣把項目所引入的cocos2d的工程裏改一下,但cocos2d的工程修改的地方有點特別!
如上圖的工程,非target!
- 到此,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測試layer,box2d世界是獨立於cocos的scene的
*
*@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__) */
// 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);
}
}
SetAsBox 函數接收了半個寬度和半個高度,這樣的話,地面盒就是 100 個單位寬(x 軸)以及 20 個單位高(y 軸)。Box2D 已被調諧使用米,千克和秒來作單位,所以你可以用米來考慮長度。然而, 改變單位系統是可能的。