1、創建一個靜態物體
創建一個靜態物體應該很簡單,在頭文件生命一下要創建新物體的函數,然後在cpp文件中實現它即可。
具體的時候先過程,首先要用createbody函數創建一個物體,然後定義一個b2bodydef變量,指定一下這個變量的type還有position。這樣的話一個最簡單的靜態物體就算是創建好了。
2、物體的相互作用
但是我們雖然創建了兩個物體但是在運行的時候發現依然沒有看到靜止的物體擋住了動態運動的物體,這就是兩個物體並沒有發生相互作用。
爲了讓兩個物體發生相互作用,我們要設置一個fixture
2. Body: Box2d 中的 Body 沒有形狀大小,不能碰撞,只具備質量(由 Fixture 的 shape 和 density 決定)、速度、位置這幾個基本屬性; Body 可以接收力和衝量的作用; 可以附着 Fixture ,附着後才具備形狀大小,可以碰撞反彈 Body 有 3 種: static: 沒有速度,不接受力和衝量的作用; dynamic: 有速度,可以接受力和衝量的作用; kinematic: 有速度,不接受力和衝量的作用。與 dynamic 碰撞不會改變原速度,與 static 碰撞不會有反應 創建 Body: b2BodyDef myBodyDef; myBodyDef.type = b2_dynamicBody; myBodyDef.position.Set(0, 20); m_body = m_world->CreateBody(&myBodyDef); 3. Fixture: Fixture 描述了物體的 形狀、密度、彈性、摩擦因數; 兩個物體發生碰撞時的反應由其 Fixture 決定; 一個 Body 可以有多個 Fixture ,Body 的重心受多個 Fixture 的影響; Fixture 中的 shape、destiny 等都是以標準單位 米、千克每平方來作爲單位的,設定的時候可以參考實際的情形; Fixture 有四種 shape : b2PolygonShape: 多邊形 b2CircleShape: 圓形 b2EdgeShape: 線 b2ChainShape: 鏈(幾條線連在一起) Friction 摩擦因數: friction 值的範圍爲 0 到 1,爲 0 表示完全沒有摩擦,爲 1 並不意味着不存在滑動; 當兩個物體發生摩擦時,摩擦的大小取決於比較小的 friction Restitution 彈性: restitution 值的範圍爲 0 到 1, 爲 0 表示完全沒有彈性,碰撞時所有的能量將全部被反彈回去; 當兩個物體發生碰撞時,碰撞的結果取決於比較大的 restitution 創建 Friction: b2PolygonShape polygonShape; polygonShape.SetAsBox(1,1); b2FixtureDef myFixtureDef; myFixtureDef.shape = &polygonShape; myFixtureDef.density = 1; myFixtureDef.friction = 0; // 摩擦因數爲 0 myFixtureDef.restitution = 1; // 彈性因數爲 1 m_body->CreateFixture(&myFixtureDef);上面的代碼片段還有解釋應該能說明爲什麼要給一個物理設置fixture,body看起來是很單一的,如果想讓他實現真實物理世界中的一些特性就要設置fixture。
fixture主要是設置物體的一些性質,和之前創建物體時候的bodydef的概念類似。
在用b2PolygonShape shape;這句話指定了物體的形狀是多邊形之後,還要對應的設置這個物體的位置。利用的就是setasbox.SetAsBox函數接收半個寬度和半個高度作爲參數,也就是說,設置出來的這個物體的尺寸是裏面的參數的兩倍大小。
void HelloWorld::addrect()
{
b2BodyDef def;
b2FixtureDef fixdef;
b2PolygonShape shape;
b2Body *b = word->CreateBody(&def);
auto sprite = Sprite::create();
def.position = b2Vec2(3,5);
def.type = b2_dynamicBody;
shape.SetAsBox(0.5,0.5);
fixdef.density = 1;
fixdef.friction = 0.3;
fixdef.shape = &shape;
b->CreateFixture(&fixdef);
addChild(sprite);
sprite->setTextureRect(Rect(0,0,0.5*2*RATIO,0.5*2*RATIO));
b->SetUserData(sprite);
}
void HelloWorld::addground()
{
b2BodyDef def;
b2PolygonShape shape;
def.position = b2Vec2(400/RATIO,0);
shape.SetAsBox(400/RATIO,0.5);
def.type = b2_staticBody;
b2Body * body = word->CreateBody(&def);
b2FixtureDef fixdef;
fixdef.density = 1;
fixdef.friction = 0.3;
fixdef.shape = &shape;
body->CreateFixture(&fixdef);
}
兩個函數,上面的一個是創建動態的物體然後下落,下面這個函數是創建一個地板,是靜態物體。之所是設置fixtrue就是爲了能讓物體之間產生相互的作用。將物體的屬性完備一些,就可以出現一些真實物理世界的情況。
3、創建漂浮的物體
創建漂浮的物體其實也很簡單,只不過是改變一下這個物體的類型爲b2_kinematicBody即可。漂浮物體和靜止物體是不一樣的,靜止物體是絕對不動的。漂浮物體的物體是不受物理世界的重力控制的。如果想讓漂浮物體真正起到漂浮的效果要怎麼辦呢,很簡單,給這個物體設置一個初速度就可以了。
def.linearVelocity = b2Vec2(1,0);設置一個只沿着x 軸方向的初速度。
4、物體的碰撞檢測
一般來說,偵聽一個事件都需要一個偵聽器.
b2ContactListener 這個類主要就是用來監聽一些物體之間的接觸的。通過實現
b2ContactListener 你就可以收到接觸數據。接觸監聽器支持幾種事件: 開始(begin),結束(end), 求解前(pre-solve), 求解後(post-solve)。
Begin事件
當兩個fixture開始有重疊時,事件會被觸發。傳感器和非傳感器都會觸發這事件。這事件只能在時間步內(譯註: 也就是b2World::step函數內部)發生。
End事件
當兩個fixture不再重疊時,事件會被觸發。傳感器和非傳感器都會觸發這事件。當一個body被摧毀時,事件也有可能被觸發。所以這事件也有可能發生在時間步之外。
Pre-Solve事件
在碰撞檢測之後,但在碰撞求解之前,事件會被觸發。這樣可以給你一個機會,根據當前情況來決定是否使這個接觸失效。 舉個例子,在回調中使用b2Contact::SetEnabled(false),你就可以實現單側碰撞的功能。每次碰撞處理時,接觸會重新生效,所以你在每一個時間步 中都應禁用那個接觸。由於連續碰撞檢測,pre-solve事件在單個時間步中有可能發生多次。
爲了測試,我準備用begin來檢驗這個監聽器的效果。
動態的物體會下落,那麼下落在地板上的時候,肯定會發生接觸,這樣就可以用這個類的一些方法來檢測了。SetContactListener利用這個函數創建一個監聽器,參數就是我們當前的這個類,this。之後便可以重新實現void HelloWorld::BeginContact(b2Contact* contact).
重新實現如下
void HelloWorld::BeginContact(b2Contact* contact)
{
if(contact->GetFixtureA()->GetBody() == groundbody||contact->GetFixtureB()->GetBody() == groundbody)
{
log("have a body in ground");
}
}
contact對象可以獲取到接觸的兩個fixture進而獲取到他們的實體,如果有一個是地板的話,那麼就說明那個自由下落的動態物體和地板發生碰撞了,這樣就顯示一個消息