大家都知道 Cocos2d-x 3.0 特別在物理引擎這塊做了一些整合
在 Box2D 和 Chipmunk 的上層做了一個新類別「Physics」來做承接
加快關於使用物理的開發
使用者可以透過改變參數來決定下層是要使用 Box2D 還是 Chipmunk
但目前 Cocos2d-x 3.0 的版本(Beta)底層還是只有 Chipmunk
box2D 還沒有引入
不過還是介紹在 Windows 底下如何更改參數
官方文件裡有寫到
只要將「CC_ENABLE_CHIPMUNK_INTEGRATION = 1」
改成「CC_ENABLE_BOX2D_INTEGRATION = 1」即可
但你可能在 VIsual Studio 2012/2013 裡面搜尋整個方案還是找不到這串巨集是定義在哪
在專案底下「按右鍵」選擇「屬性」
在「C/C++」層的「前置處理器」中找到「前置處理器定義」
並將紅色框標記起來的「CC_ENABLE_CHIPMUNK_INTEGRATION = 1」改成
「CC_ENABLE_BOX2D_INTEGRATION = 1」即可
只是在目前 Cocos2d-x 3.0(Beta)的版本改了也沒用
底層還是以「Chipmunk」來實作
b2World 改為 PhysicsWorld
要建立一個物理世界
b2World 是不可或缺的
所有的物理運作都得加在它上面才能運行
因為在每個場景中,我們得自己宣告一個 b2World
並定義它的重力和其他參數
而在新版的物理引擎中則使用的是「PhysicsWorld」
而且我們不需要去特別宣告它或定義它參數
而是在建立「Scene」的時候就要決定是否使用到「Physics」
一旦決定使用後,系統(Scene)會自動產生一個「PhysicsWorld」
我們只要去取用即可
class PhysicsMain : public cocos2d::Layer { public: static Scene* createScene(); virtual bool init(); CREATE_FUNC(PhysicsMain); private: PhysicsWorld* m_World; void SetPhysicsWorld(PhysicsWorld* _world){ this->m_World = _world; }
為了在取用的時候指定方便
我們特別宣告一個函式「SetPhysicsWorld」
並將得到的 PhyscisWorld 指定給成員變數 m_World
Scene* PhysicsMain::createScene() { auto scene = Scene::createWithPhysics(); //auto scene = Scene::create(); scene->getPhysicsWorld()->setDebugDrawMask(PhysicsWorld::DEBUGDRAW_NONE); auto layer = PhysicsMain::create(); layer->SetPhysicsWorld(scene->getPhysicsWorld()); scene->addChild(layer); return scene; }
而在建立 Scene 的時候
如果要建立一個有物理世界的場景
則我們得使用「createWithPhysics()」的靜態函式
若沒有要使用,則就如以前一樣,使用「create()」即可
而「setDebugDrawMask」的函式可以選擇是否要顯示 Debug 的線
也就是我們以前得用 b2DebugDraw 來實作的功能
現在也只要用這一行指定就可以了
即使不使用任何的圖片,我們還是可以看到物理環境的運作
最後在從 scene 中取得我們的「PhysicsWorld」即可
Sprite 和 Physics 的綁定
在以前使用 Box2D 的時候
我們得定義一個「b2BodyDef」
並將「userData」指定為某個「Sprite」
而且我們得在「update」函式中
根據目前物件(b2Body)的位置來更新 userData(Sprite)的位移和旋轉
auto sprite = Sprite::create("sprite.png"); b2CircleShape *circle = new b2CircleShape(); circle->m_radius = 5 / 64; b2FixtureDef fd; fd.density = 3; fd.friction = 0; fd.restitution = 0; fd.shape = circle; b2BodyDef bodyDef; bodyDef.type = b2_dynamicBody; bodyDef.position.Set(p.x / 64, p.y / 64); bodyDef.userData = sprite; b2Body *particleBody = this->m_World->CreateBody(&bodyDef); particleBody->CreateFixture(&fd);
在 update 的函式中
this->m_World->Step(1 / 60, 8, 1); for (b2Body* bd = this->m_World->GetBodyList(); bd; bd->GetNext()) { if (bd->GetUserData() != NULL) { Sprite *w = (Sprite*) bd->GetUserData(); w->setPosition(Point(bd->GetPosition().x * 64, bd->GetPosition().y * 64)); w->setRotation(-1 * CC_RADIANS_TO_DEGREES(bd->GetAngle())); } }
在新版 Physics 裡
Sprite 本身就有「body」的屬性
Sprite 也多了一個「setPhysicsBody」的函式
可以將定義好的「PhysicsBody」指定給 Sprite
這樣一來,我們就可以不需要在「update」函式中更新 Sprite 的位置和旋轉了
auto sprite = Sprite::create("sprite.png"); auto material = PhysicsMaterial::PhysicsMaterial(10, 0.0f, 0.1f); auto spriteBody = PhysicsBody::createCircle(4, material, Point::ZERO); sprite->setPosition(p); sprite->setPhysicsBody(spriteBody); this->addChild(sprite);
當在初始化的時候
只要宣告好 Sprite 和 PhysicsBody
透過 Sprite 的 「setPhysicsBody」函式,將 PhysicsBody 指定進去
Sprite 就會有 Body 的屬性
不需要在 update 中去更新 Sprite 的位置和旋轉
若你還是想在 update 中取得每個物件
也可以透過下列程式碼中取得
Vector<PhysicsBody*>::const_iterator d = this->m_World->getAllBodies().begin(); for (; d != this->m_World->getAllBodies().end(); d++) { PhysicsBody *body = (*d); Sprite *sprite = ((Sprite*)(*d)->getNode()); }
原文链接:http://kw0006667.wordpress.com/2014/02/14/cocos2d-x-3-0-physics-基本設定/