實例介紹Cocos2d-x中Box2D物理引擎:HelloBox2D

咱們經過一個實例介紹一下,在Cocos2d-x 3.x中使用Box2D物理引擎的開發過程,熟悉這些API的使用。這個實例運行後的場景如圖所示,當場景啓動後,玩家能夠觸摸點擊屏幕,每次觸摸時候,就會在觸摸點生成一個新的精靈,精靈的運行自由落體運動。
  



html

HelloBox2D實例算法

使用Box2D引擎進行開發過程,如圖12-15所示。下面咱們就按照這個步驟介紹一下代碼部分。首先看一下看HelloWorldScene.h文件,它的代碼以下:安全

[html] view plaincopy微信

 

  1. #ifndef __HELLOWORLD_SCENE_H__  函數

  2. #define __HELLOWORLD_SCENE_H__  測試

  3.   

  4.   

  5. #include "cocos2d.h"  網站

  6. #include "Box2D/Box2D.h"                                                ①  this

  7.   

  8.   

  9. #define PTM_RATIO 32                                                    ②  spa

  10.   

  11.   

  12. class HelloWorld : public cocos2d::Layer  .net

  13. {  

  14.     b2World* world;                                                     ③  

  15.   

  16.   

  17. public:  

  18.     static cocos2d::Scene* createScene();  

  19.     virtual bool init();    

  20.   

  21.   

  22.     virtual void update(float dt);                                              ④  

  23.     virtual bool onTouchBegan(cocos2d::Touch* touch, cocos2d::Event* event);            ⑤  

  24.   

  25.   

  26.     CREATE_FUNC(HelloWorld);  

  27.       

  28.     void initPhysics();                                                     ⑥  

  29.     void addNewSpriteAtPosition(cocos2d::Vec2 p);                               ⑦  

  30.   

  31.   

  32. };  

  33.   

  34.   

  35. #endif // __HELLOWORLD_SCENE_H__  



上述第①行代碼#include "Box2D/Box2D.h"是引入使用Box2D引擎須要頭文件。第②行代碼#define PTM_RATIO 32是定義宏PTM_RATIO,PTM_RATIO是屏幕上多少像素爲1米,32表示屏幕上32像素表示1米,在Box2D中單位使用MKS公制系統,即:長度單位採用米,質量單位採用千克,時間單位採用秒。
代碼第③行world是聲明物理世界b2World成員變量。第④行代碼是遊戲循環函數。第⑤行代碼是觸摸點擊響應函數。第⑥行代碼是聲明初始化物理引擎函數initPhysics。第⑦行是聲明addNewSpriteAtPosition函數,是在觸摸點建立一個精靈對象。
HelloWorldScene.cpp中HelloWorld::init()函數代碼以下:

[html] view plaincopy

 

  1. bool HelloWorld::init()  

  2. {  

  3.     if ( !Layer::init() )  

  4.     {  

  5.         return false;  

  6.     }  

  7.   

  8.   

  9.     Size visibleSize = Director::getInstance()->getVisibleSize();  

  10.     Vec2 origin = Director::getInstance()->getVisibleOrigin();  

  11.   

  12.   

  13.     // 初始化物理引擎  

  14.     this->initPhysics();                                                 ①  

  15.   

  16.   

  17.     setTouchEnabled(true);                                                

  18.     //設置爲單點觸摸  

  19.     setTouchMode(Touch::DispatchMode::ONE_BY_ONE);                            

  20.     //開始遊戲循環  

  21.     scheduleUpdate();                                                   ②  

  22.   

  23.   

  24.     return true;  

  25. }  



上述代碼第①行調用initPhysics()函數初始化物理引擎。第②行代碼scheduleUpdate()是開始遊戲循環,一旦開啓遊戲循環就會回調HelloWorld::update(float dt)函數。
HelloWorldScene.cpp中初始化物理引擎HelloWorld::initPhysics()函數代碼以下:

[html] view plaincopy

 

  1. void HelloWorld::initPhysics()  

  2. {  

  3.     Size s = Director::getInstance()->getVisibleSize();  

  4.       

  5.     //重力參數  

  6.     b2Vec2 gravity;                                                         ①  

  7.     gravity.Set(0.0f, -10.0f);                                              ②  

  8.     //建立世界  

  9.     world = new b2World(gravity);                                           ③  

  10.     // 容許物體是否休眠  

  11.     world->SetAllowSleeping(true);                                           ④  

  12.     // 開啓連續物理測試  

  13.     world->SetContinuousPhysics(true);                                       ⑤  

  14.       

  15.     //地面物體定義  

  16.     b2BodyDef groundBodyDef;                                            ⑥  

  17.     //左下角  

  18.     groundBodyDef.position.Set(0, 0);                                       ⑦  

  19.   

  20.   

  21.     //建立地面物體  

  22.     b2Body* groundBody = world->CreateBody(&groundBodyDef);                      ⑧  

  23.   

  24.   

  25.     //定義一個有邊的形狀  

  26.     b2EdgeShape groundBox;                                              ⑨  

  27.   

  28.   

  29.     // 底部  

  30.     groundBox.Set(b2Vec2(0,0), b2Vec2(s.width/PTM_RATIO,0));                        ⑩  

  31.     //使用夾具固定形狀到物體上  

  32.     groundBody->CreateFixture(&groundBox,0);                                 ⑪  

  33.   

  34.   

  35.     // 頂部  

  36.     groundBox.Set(b2Vec2(0,s.height/PTM_RATIO),   

  37.                     b2Vec2(s.width/PTM_RATIO,s.height/PTM_RATIO));                    

  38.     groundBody->CreateFixture(&groundBox,0);                                   

  39.   

  40.   

  41.     // 左邊  

  42.     groundBox.Set(b2Vec2(0,s.height/PTM_RATIO), b2Vec2(0,0));                           groundBody->CreateFixture(&groundBox,0);                                   

  43.   

  44.   

  45.     // 右邊  

  46.     groundBox.Set(b2Vec2(s.width/PTM_RATIO,s.height/PTM_RATIO),   

  47.                         b2Vec2(s.width/PTM_RATIO,0));                                 

  48.     groundBody->CreateFixture(&groundBox,0);                                   

  49.   

  50.   

  51. }  



代碼第①行b2Vec2 gravity是聲明重力變量,b2Vec2是一個二維矢量,它的兩個屬性爲浮點數x和y,表示在x軸和y軸方向的矢量。第②行代碼gravity.Set(0.0f, -10.0f)是設置矢量值,其中(0.0f, -10.0f)表示只有重力做用物體,-10.0f表示沿着y軸向下。
第③行代碼world = new b2World(gravity)是建立物理世界b2World對象,這裏採用了new建立物理世界對象,在C++中new關鍵字分配內存,釋放內存是delete關鍵字。World是成員變量,須要本身釋放成員變量通常是在析構函數中釋放,代碼以下:
HelloWorld::~HelloWorld()
{
    CC_SAFE_DELETE(world); 
}
其中CC_SAFE_DELETE(world)是安全釋放world變量,CC_SAFE_DELETE宏表明安全釋放內存。
第④行代碼world->SetAllowSleeping(true)是容許物體睡眠與否,若是容許休眠,能夠提升物理世界中物體的處理效率,只有在發生碰撞時才喚醒該對象。
第⑤行代碼world->SetContinuousPhysics(true)是開啓連續物理測試[ 開啓連續物理測試,這是由於計算機只能把一段連續的時間分紅許多離散的時間點,再對每一個時間點之間的行爲進行演算,若是時間點的分割不夠細緻,速度較快的兩個物體碰撞時就可能會產生「穿透」現象,開啓連續物理將啓用特殊的算法來避免該現象。]。
第⑥行代碼是聲明形狀定義(b2BodyDef)變量。第⑦行代碼groundBodyDef.position.Set(0, 0)是設置形狀的位置。第⑧行代碼b2Body* groundBody = world->CreateBody(&groundBodyDef)是經過形狀定義變量groundBodyDef建立地面物體。
第⑨行代碼是聲明一個有邊形狀定義b2EdgeShape變量,第⑩行代碼groundBox.Set(b2Vec2(0,0), b2Vec2(s.width/PTM_RATIO,0))是設置有邊形狀的開始位置(0,0)和結束位置(s.width/PTM_RATIO,0),s.width/PTM_RATIO是將像素換算成米。第⑪行代碼是使用夾具固定形狀到物體上。用相似的函數定義頂部、左邊和右邊的物體。
HelloWorldScene.cpp中建立精靈HelloWorld::addNewSpriteAtPosition函數代碼以下:

[html] view plaincopy

 

  1. void HelloWorld::addNewSpriteAtPosition(Vec2 p)  

  2. {      

  3.     log("Add sprite %0.2f x %02.f",p.x,p.y);  

  4.   

  5.   

  6.     //建立物理引擎精靈對象  

  7.     auto sprite = Sprite::create("BoxA2.png");                                  ①  

  8.     sprite->setPosition( Vec2( p.x, p.y) );  

  9.     this->addChild(sprite);  

  10.   

  11.   

  12.     //物體定義  

  13.     b2BodyDef bodyDef;                                                  ②  

  14.     bodyDef.type = b2_dynamicBody;                                          ③  

  15.     bodyDef.position.Set(p.x/PTM_RATIO, p.y/PTM_RATIO);                         ④  

  16.     b2Body *body = world->CreateBody(&bodyDef);                              ⑤  

  17.     body->SetUserData(sprite);                                               ⑥  

  18.   

  19.   

  20.     // 定義2米見方的盒子形狀  

  21.     b2PolygonShape dynamicBox;                                          ⑦  

  22.     dynamicBox.SetAsBox(1, 1);                                          ⑧  

  23.   

  24.   

  25.     // 夾具定義  

  26.     b2FixtureDef fixtureDef;                                                ⑨  

  27.     //設置夾具的形狀  

  28.     fixtureDef.shape = &dynamicBox;                                         ⑩  

  29.     //設置密度  

  30.     fixtureDef.density = 1.0f;                                              ⑪  

  31.     //設置摩擦係數  

  32.     fixtureDef.friction = 0.3f;                                             ⑫  

  33.     //使用夾具固定形狀到物體上    

  34.     body->CreateFixture(&fixtureDef);                                        ⑬  

  35.   

  36.   

  37. }  



上述代碼第①行是建立精靈(Sprite)對象,精靈(Sprite)對象與物理引擎物體是沒有關係,咱們須要在遊戲循環函數中更新。
代碼第②行是聲明動態物體定義變量,代碼第③行bodyDef.type = b2_dynamicBody是設置物體類型爲動態物體,物體分爲靜態和動態物體。第④行代碼是設置物體的位置,它的單位是米。第⑤行代碼b2Body *body = world->CreateBody(&bodyDef)是建立物體對象。第⑥行代碼body->SetUserData(sprite)是將精靈放置到物體的UserData屬性中,這樣便於咱們從物體中獲取相關聯的物體。
第⑦行代碼b2PolygonShape dynamicBox是聲明多邊形形狀定義變量。第⑧行代碼dynamicBox.SetAsBox(1, 1)是設置多邊形爲矩形盒子形狀,因爲座標原點在盒子的左下角,SetAsBox是設置盒子的中心爲(1,1),那麼這個盒子的就是2米見方的大小。
第⑨行代碼是b2FixtureDef fixtureDef是聲明夾具定義變量。第⑩行代碼是設置夾具的形狀。第⑪行代碼fixtureDef.density = 1.0f是設置形狀的密度。第⑫行代碼fixtureDef.friction = 0.3f是設置摩擦係數,範圍是0.0~1.0之間。第⑬行代碼body->CreateFixture(&fixtureDef) 是使用夾具固定形狀到物體上,這樣物體就有了形狀。
HelloWorldScene.cpp中游戲循環函數HelloWorld::update代碼以下:

[html] view plaincopy

 

  1. void HelloWorld::update(float dt)  

  2. {  

  3.     float timeStep = 0.03f;   

  4.     int32 velocityIterations = 8;     

  5.     int32 positionIterations = 1;     

  6.   

  7.   

  8.     world->Step(timeStep, velocityIterations, positionIterations);  

  9.   

  10.   

  11.     for (b2Body* b = world->GetBodyList(); b; b = b->GetNext())                       ①  

  12.     {  

  13.         if (b->GetUserData() != nullptr) {                                     

  14.             Sprite* sprite = (Sprite*)b->GetUserData();    

  15.             sprite->setPosition( Vec2( b->GetPosition().x *   

  16.                 PTM_RATIO, b->GetPosition().y * PTM_RATIO) );      

  17.             sprite->setRotation( -1 * CC_RADIANS_TO_DEGREES(b->GetAngle()) );  

  18.         }  

  19.     }                                                                           ②  

  20. }  



其中代碼①~②這段代碼能夠同步物理引擎中的物體與精靈位置和狀態。

 

 

 

更多內容請關注國內第一本Cocos2d-x 3.2版本圖書《Cocos2d-x實戰:C++卷》

本書交流討論網站:http://www.cocoagame.net
更多精彩視頻課程請關注智捷課堂Cocos課程:http://v.51work6.com

歡迎加入Cocos2d-x技術討論羣:257760386

 

 

 

 

 

歡迎關注智捷iOS課堂微信公共平臺

相關文章
相關標籤/搜索