1. 程式人生 > >(轉載)Box2D v2.3.0 使用者手冊中文版(第1章)-導言

(轉載)Box2D v2.3.0 使用者手冊中文版(第1章)-導言

Chapter 1 導言

1.1 關於

Box2D 是一個用於遊戲的 2D 剛體模擬庫。程式設計師可以在他們的遊戲裡使用它,它可以使物體的運動更加真實,並讓遊戲世界看起來更具互動性。從遊戲引擎的視角來看,物理引擎就是一個程式性動畫 (proceduralanimation)的系統。

(譯註: 做動畫常有兩種方法, 一種是預先準備好動畫所需的資料,比如圖片,再一幀一幀地播放。另一種是以一定方法,動態計算出動畫所需的資料,根據資料再進行繪圖。
從這種角度看,預先準備的,可稱為資料性動畫,動態計算的可稱為程式性動畫。
這個區別,就類似以前我們做歷史題和數學題,做歷史題,記憶很重要,也就是答案需要預先準備好的。做數學題,方法就很重要,答案是需要用方法推匯出來的。
Box2D就是用物理學的方法,推匯出那遊戲世界物體的位置,角度等資料。而Box2D也僅僅推匯出資料,至於得到資料之後怎麼處理就是程式設計師自己的事情了。)

Box2D 是用可移植的 C++ 寫成的。引擎中大部分型別的定義都有 b2 字首,希望這能有效的消除它和你的遊戲引擎之間的名字衝突。

1.2 先決條件

在此,我假定你已經熟悉了基本的物理學概念,例如質量、力、扭矩和衝量。如果沒有,請先查詢一下Google搜尋和維基百科。
Box2D是遊戲開發者大會(Game Developer Conference,GDC)的物理學教程的一部分。你可以從box2d.org的下載頁面獲得這些教程。
因為 Box2D 是用 C++ 寫成的,所以你應該具備 C++ 程式設計的經驗。Box2D 不應該成為你的第一個 C++ 程式專案。你應該已經能熟練地編譯,連結和除錯了。

注意
Box2D 不應該成為你的第一個 C++ 程式專案。你應該已經能熟練地編譯,連結和除錯了。網路上有很多關於C++的資料。

1.3 關於手冊

這個手冊包含了主要的Box2D的API,但並不是每一個都包含了 。你可以通過閱讀Box2D自帶的testbed程式的程式碼來學習更多的東西。而且Box2D程式碼的註釋已經按照Doxygen格式編寫,可以很容易的建立超連結形式的API文件。
這個手冊只在新版本釋出的時候更新。因此相比版本庫中的程式碼版本,它可能已經過時了。

1.4 反饋和報告BUG

如果你有關於Box2D的問題或者反饋意見,請在論壇留言。這也是社群討論的好地方。
Box2D使用 Google code project來跟蹤問題。這是個很好的方式,它可以確保你的問題不會淹沒在論壇之中。
請在這裡列出BUG和功能需求:

http://code.google.com/p/box2d/
如果你能提供更有效的細節的話,就能確保你的問題得到解決。一個用於復現問題的testbed用例是很有意義的。你可以在隨後章節讀到和testbed相關的內容。

1.5 核心概念

Box2D 中有一些基本的概念和物件,這裡我們先做一個簡要的定義,在隨後的章節裡會有更詳細的描述。

形狀(shape)

形狀是一個2D的幾何物件。例如圓或多邊形。

剛體(rigid body)

一塊十分堅硬的物質,它上面的任何兩點之間的距離都是完全不變的。它們就像鑽石那樣堅硬。在後面的討論中,我們用物體(body)來指代剛體。

夾具(fixture)

夾具將形狀繫結到物體上,並新增密度(density)、摩擦(friction)和恢復(restitution)等材料特性。夾具還將形狀放入碰撞系統(碰撞檢測(Broad Phase))中,以使之能與其他形狀相碰撞。

(譯註: 一個物體和另一物體碰撞, 碰撞後速度和碰撞前速度的比值會保持不變,這比值就叫恢復係數。)
(譯註: Broad Phase是碰撞檢測的一個子階段, 將空間分割, 每個空間對應一個子樹, 物體就放到樹中, 不同子樹內的物體不可能相交不用去計算, 在同一個子樹由對應的演算法再計算出接觸點等資訊。因為這是遠距碰撞檢測,就叫Broad Phase, 接下來還有Narrow Phase。)

約束(constraint)

約束(constraint)就是消除物體自由度的物理連線。一個2D物體有3個自由度(兩個平移座標和一個旋轉座標)。如果我們把一個物體釘在牆上(像擺錘那樣),那我們就把它約束到了牆上。這樣,此物體就只能繞著這個釘子旋轉,因此這個約束消除了它 2 個自由度。

接觸約束(contact constraint)

一種防止剛體穿透,並模擬摩擦和恢復的特殊約束。你不必建立接觸約束,它們會自動被 Box2D 建立。

關節(joint)

它是一種用於把兩個或更多的物體固定到一起的約束。Box2D 支援若干種關節型別: 旋轉、稜柱、距離等等。有些關節擁有限制(limits)和馬達(motors)。

關節限制(joint limit)

關節限制限定了關節的運動範圍。例如,人類的胳膊肘只能做某一範圍角度的運動。

關節馬達(joint motor)

關節馬達能依照關節的自由度來驅動所連線的物體。例如,你可以使用馬達來驅動胳膊肘的旋轉。

世界(world)

物理世界就是相互作用的物體,夾具和約束的集合。Box2D 支援建立多個世界,但這通常是不必要或不推薦的。

求解器(solver)

物理世界使用求解器來推算時間,求解接觸和關節約束。Box2D的求解器是一種高效能的迭代求解器,它會順序執行N次,這裡的N是約束的個數。

(譯註: 即演算法的複雜度為O(N)。)

連續碰撞(continuous collision)

求解器使用時域上的離散時間步來推算物體狀態。如果沒有特殊處理的話,這會導致隧穿效應。

(譯註: 假設我們採用1s的固定時間間隔來推算一個物理系統的運動。那麼如果這個系統中有兩個物體在某一秒的0.5s的時刻,發生碰撞的話。死板的採用固定時間間隔計算的方法,就會導致物體實際上越過了碰撞點的現象發生,這就是隧穿效應。解決的辦法顯然是要估算出碰撞發生的時刻,並做相應的處理,這也是下一段提到的TOI的含義。)


Box2D擁有特殊的演算法來處理隧穿效應。首先,碰撞演算法能夠在兩個物體的運動過程中進行插值運算,以找到首次碰撞時間 (the first time of impact,TOI)。接著,一個分步求解器將物體移動到它們的TOI時刻,並對碰撞求解。

1.6 模組

Box2D由三個模組組成: 通用模組(Common),碰撞模組(Collision) 和力學模組(Dynamics). 通用模組包含了記憶體分配、數學和配置的程式碼。碰撞模組定義形狀、碰撞檢測和碰撞的函式或佇列。最終力學模組提供對世界、物體、夾具和關節的模擬。

1.7 單位

Box2D使用浮點數,所以必須使用公差來保證它正常工作。這些公差已經被調諧得適合米-千克-秒(MKS)單位制。尤其是,Box2D已被調諧得能良好地處理0.1到10米之間的移動物體。這意味著從罐頭盒到公共汽車大小的物件都能良好地工作。靜態的物體就算大到50米都沒有問題。
作為一個2D物理引擎,使用畫素作為單位是很誘人的。但很不幸,那將導致不良的模擬,也可能會造成古怪的行為。一個200畫素長的物體在Box2D看來就有45層建築那麼大。

注意
Box2D 已被調諧至 MKS 單位。移動物體的尺寸應該保持在大約 0.1 到 10 米之間。當你渲染場景和角色時, 可能要用到一些比例縮放系統。Box2D自帶的testbed例子,使用了OpenGL的視口變換。不要使用畫素!!!

最好把Box2D中的物體看作是被貼上了你的藝術創作品的移動廣告板。這個廣告板在一個以米為單位的系統裡運動,但你可以利用簡單的比例因子把它轉換為畫素座標。之後就可以使用這些畫素座標去確定你的精靈(sprites)的位置,等等。你也可以將它的座標軸翻轉過來。

(譯註: 座標軸翻轉的含義是比例因子可以為負數。)

Box2D裡的角使用弧度制。物體的旋轉角度以弧度方式儲存,並可以無限增大。如角度變得太大,可考慮將角度進行規範化。(使用b2Body::SetAngle)

注意
Box2D使用弧度,而不是度。

1.8 工廠和定義

快速記憶體管理在 Box2D API 的設計中擔當了一箇中心角色。所以當你建立一個 b2Body 或一個 b2Joint時,你需要呼叫 b2World 的工廠函式(factory functions)。你不應以別的方式為這些型別分配記憶體。
這些是建立函式:

b2Body* b2World::CreateBody(const b2BodyDef* def)
b2Joint* b2World::CreateJoint(const b2JointDef* def)

這些是對應的銷燬函式:

void b2World::DestroyBody(b2Body* body)
void b2World::DestroyJoint(b2Joint* joint)

當你建立物體或關節時,需要提供定義(definition)。這些定義包含了建立物體或關節時所需的所有資訊。使用這樣的方法,我們能夠預防構造錯誤,保持較少的函式引數數量,提供有意義的預設值,並減少訪問子(accessor)的個數。
因為fixture必須有父body,所以要使用b2Body的工廠方法來建立並銷燬它們。

b2Fixture* b2Body::CreateFixture(const b2FixtureDef* def)
void b2Body::DestroyFixture(b2Fixture* fixture)

也有個簡便的方法直接用形狀和密度來建立fixture。

b2Fixture* b2Body::CreateFixture(const b2Shape* shape, float32 density)

工廠並不保留定義的引用,因此你可以在棧上建立定義,並在臨時資源中儲存它們。