既然已有了cocos2d-x,為什麼還要Box2d呢,是因為cocos2d-x作為一個圖像引擎,只是用於顯示圖像,圖像之間可以任意的重合,如果想要做到類物理學的碰撞等運動效果,就需要用到Box2d這個物理引擎用來模仿物理世界中的物體;
本講主要簡單講述如何創建動態物體,靜態物體,漂浮物體,以及它們與圖像的綁定;
下面直接通過一個例子來看三種物體的創建方法;
首先需要說明的一點是:在Box2d中,使用的單位是米,而不是像素,所以,在進行位置轉換的時候,需要按比例縮放,Box2d中,比較理想的距離大小是10米,所以,得對屏幕寬高進行一定的比例縮放(如下面例子中定義的RADIO,就是我定義的比例);
HelloWorldScene.cpp
#include "HelloWorldScene.h" #define RADIO 80 Scene* HelloWorld::createScene() { // 'scene' is an autorelease object auto scene = Scene::create(); // 'layer' is an autorelease object auto layer = HelloWorld::create(); // add layer as a child to scene scene->addChild(layer); // return the scene return scene; } // on "init" you need to initialize your instance bool HelloWorld::init() { ////////////////////////////// // 1. super init first if ( !Layer::init() ) { return false; } world = new b2World(b2Vec2(0,-10)); //x 方向加速度為0,y方向加速度為10 world->SetContactListener(this); // 添加物體撞擊事件監聽 addGround(); addRect(); scheduleUpdate(); // 開始執行handler,第幀執行一次update方法 return true; } void HelloWorld::update(float dt){ world->Step(dt,8,3); // 三個參數分別表示當前幀和最後一幀之間的時間間隔,由於update方法是程序每一幀執行一次,所以直接傳入幀頻dt;
//第二個參數表示速度迭代次數,官方建議8;
//第三個參數表示位置迭代次數,官方建議3; Sprite *s; for(b2Body *b = world->GetBodyList();b;b= b->GetNext()){ if(b->GetUserData()){ s = (Sprite*)b->GetUserData(); s->setPosition(b->GetPosition().x * RADIO ,b->GetPosition().y *RADIO); // 更新物體的位置 } } } void HelloWorld::BeginContact(b2Contact* contact){ // b2ContactListener物體發生碰撞時的回調接口 log("contact?"); if(contact->GetFixtureA()->GetBody() == ground ||contact->GetFixtureB()->GetBody() == ground){ log("yeah,contacted!"); } } void HelloWorld::addRect(){ // 添加一個動態的Rect,並且綁定一個Sprite; b2BodyDef def; def.type = b2_dynamicBody; // 指定type為動態物體 @1 def.position = b2Vec2(3,1); // 起始位置(3,1) def.linearVelocity = b2Vec2(0,10); // (初始)線性速度,如果type為漂浮的,則物體會沒這個方向做勻速運動,如果為動態,則會進行預先設定的加速度進行速度變換; b2PolygonShape shape; shape.SetAsBox(0.5,0.5); // 設置一個Shape,兩個參數分別表示左半邊和上半邊的大小,所以,這裡兩個0.5其實就定義了一個1x1的塊 b2FixtureDef fixtureDef; fixtureDef.density = 1; // 指定物體密度 fixtureDef.friction = 0.3; // 指定物體摩擦 fixtureDef.shape = &shape; // 指定物體的shape b2Body *body = world->CreateBody(&def); auto s = Sprite::create(); s->setTextureRect(Rect(0 , 0, 30, 30)); // 設置sprite所顯示的區域 addChild(s); body->CreateFixture(&fixtureDef); // 設置FixtureDef之後,兩個物體之間就會有碰撞的效果了,如果沒有碰撞的效果,則物體會一直沿某一個方向不停運動; body->SetUserData(s); // 將Sprite綁定到物體上 } void HelloWorld::addGround(){ //添加一個靜態物體,在為裡為添加到底部,阻止上一步中創建的自由落體的物體 b2BodyDef def; def.type = b2_staticBody; def.position = b2Vec2(0, 0); b2PolygonShape shape; shape.SetAsBox(400/RADIO, 10 / RADIO); // 設置物體大小 ground = world->CreateBody(&def); auto s = Sprite::create(); s->setTextureRect(Rect(0,0,1600,40)); b2FixtureDef fixtureDef; fixtureDef.density = 0.5; fixtureDef.friction = 0.3; fixtureDef.shape = &shape; addChild(s); ground->CreateFixture(&fixtureDef); ground->SetUserData(&def); }
HelloWorldScene.h
#ifndef __HELLOWORLD_SCENE_H__ #define __HELLOWORLD_SCENE_H__ #include "cocos2d.h" #include <Box2D/Box2D.h> USING_NS_CC; class HelloWorld : public Layer,public b2ContactListener { private : b2World *world; b2Body *ground; public: // there's no 'id' in cpp, so we recommend returning the class instance pointer static cocos2d::Scene* createScene(); // Here's a difference. Method 'init' in cocos2d-x returns bool, instead of returning 'id' in cocos2d-iphone virtual bool init(); // a selector callback void menuCloseCallback(cocos2d::Ref* pSender); // implement the "static create()" method manually CREATE_FUNC(HelloWorld); virtual void update(float dt); void addRect(); void addGround(); /// Called when two fixtures begin to touch. virtual void BeginContact(b2Contact* contact) ; }; #endif // __HELLOWORLD_SCENE_H__
@1: 這裡的type有三種類型如下