2008年2月11日 星期一

Hello Box2D

教你怎樣用Box2D,一個基於C++語言的物理模擬引擎
個人認為它的模擬效果比ape更好,速度也更快
所以就推了

底下是"哈囉世界"的中文翻譯
我也已經把範例中的程式碼從C++轉成AS3了

不過建議最好還是對物理與幾何有基本認知,不然應該還是會有火星文的感覺...囧rz

參考資料:
Official Site
http://www.box2d.org/manual.html

##CONTINUE##
建立世界

每個Box2D專案都是從world物件的建立開始的,它是負責管理記憶體、物件和模擬的中心。
要建立一個world物件,首先我們需要為世界定義一個邊界框(bounding box),Box2D使用邊界框來加速碰撞的偵測。尺寸並不是很重要,但是一個比較好的搭配會加速模擬的效能。此外,把尺寸設得大一點會比設得小更好。

var worldAABB:b2AABB = new b2AABB();
worldAABB.minVertex.Set(-rect.x, -rect.y);
worldAABB.maxVertex.Set(rect.x*2, rect.y*2);


接下來我們定義重力的向量。是的,妳可以讓重力朝向側邊(不然你也可以旋轉你的螢幕)。我們也告訴world物件允許body物件在它們靜止的時候進入睡眠狀態。一個睡著的body物件不會需要任何的模擬。

var gravity:b2Vec2 = new b2Vec2(0, 600);
var sleep:Boolean = true;


現在我們可以建立world物件了。一般我們會在程式的開頭(heap)中建立world物件,並把它的指標(pointer)儲存在你的遊戲結構之一。但是在程式堆疊(stack)中建立也是可以的。

var world:b2World = new b2World(worldAABB, gravity, sleep);

所以現在我們已經有了自己的物理世界,讓我們開始加點東西進去吧。


建立地板

Body物件是經由下面的步驟建立的:
1. 使用幾何(geometry)、摩擦力(friction)、密度(density)來定義一個shape物件。
2. 使用shape陣列、位置(position)、速度(velocity)來定義一個body物件。
3. 使用世界物件來建立body物件

所以現在我們來建立一個box定義。在定義中的資料會被Box2D複製起來,所以你可以在程式堆疊(stack)中建立它們,或者是把它們寫到你的程式架構之中。這會允許你使用同一個shape定義來建立不同的物件。底下是shape定義的建立。

var groundBoxDef:b2BoxDef = new b2BoxDef();
groundBoxDef.extents.Set(rect.x, 5);
groundBoxDef.density = 0;


範圍(extents)只是一個向量,用來代表box的一半長與一半寬。所以在這個範例中地面是一百個單位寬(X軸)與二十個單位高(Y軸)。Box2D使用的單位是公尺、公斤、秒。所以你可以把範圍(extents)的單位當作是公尺。但要改變單位系統也是可以的,這在後面會提到。

密度(desity)被指定為零。如果所有被附加在body物件上的shape物件都具有零的密度,那麼這個body物件就會被視作是靜止的。

現在我們來建立一個body物件。首先我們需要一個body定義。在body定義之中我們指定body物件的初始位置以及它的shape陣列。在這個範例中只有一個shape物件。

var groundBodyDef:b2BodyDef = new b2BodyDef();
groundBodyDef.position.Set(rect.x/2, rect.y-5);
groundBodyDef.AddShape(groundBoxDef);


body定義被當作參數傳入world中來建立body物件

var ground:b2Body = world.CreateBody(groundBodyDef);

再說一次,Box2D不會保持shape定義或是body定義的參考,它把所有的資料都複製到body物件的結構之中。

注意,每個shape物件都必須從屬於一個body物件,即使shape物件是靜止的也是一樣。因為這對靜止的body物件來說,如此能夠讓內部的程式碼更一致,也能夠減少一些潛在的錯誤。

此外你也許注意到了一個模式。大多數的Box2D型別都是以b2開始的。這是為了減少你程式碼中名稱衝突的可能性。


建立一個動態物件

所以現在我們有了一個地板。我們可以使用相同的技巧來建立一個動態物件。主要的差別除了尺寸之外,就是shape定義的密度大於零。這會讓Box2D把這個body物件視做是動態的。底下是建立動態物件的程式碼。

var objBoxDef:b2BoxDef = new b2BoxDef();
objBoxDef.extents.Set(h/2, v/2);
objBoxDef.friction = .3;
objBoxDef.density = 1;
objBoxDef.restitution = .2;
var objBodyDef:b2BodyDef = new b2BodyDef();
objBodyDef.AddShape(objBoxDef);
objBodyDef.position.Set(x, y);
var obj:b2Body = world.CreateBody(objBodyDef);


以上就是初始化的作業,現在我們可以開始來模擬了


模擬世界

所以我們已經初始化了地板物件以及一個方塊物件。現在我們準備好交給牛頓力學做它該做的事了,我們只需要注意一些東西。

Box2D使用一些計算程式,像是integrator。Integrator會在非連續的時間點之中計算物理方程式。跟視覺暫留是一樣的原理,本質是在螢幕上有一個不停翻書的動作。所以我們需要指定一個時間間隔(time step)給Box2D。一般遊戲的物理引擎都使用跟60HZ或是1/60秒至少一樣快的時間間隔。當然你也可以使用一個比較大的時間間隔,但是你就必須更小心的設定你的世界中的各項定義。我們也不喜歡時間間隔改變太多。所以不用把時間間隔綁定到你的影格速率上(除非你真的真的非常需要這樣做)。如果你真的這樣做,請在我的留言板上留言給我,因為你需要修改一些Box2D的設定。沒做什麼的話,底下就是時間間隔的定義。

var timeStep:Number = 1/60;

除了integrator之外,還有constraint solver。constraint solver負責在同一時間內處理模擬中所有的約束行為。一個單獨的約束行為可以被處理得很好。但是在複數個約束行為的情況下,當我們處理其中一個約束時,我們也會稍微的影響到其他的約束。所以為了得到一個好的結果,我們需要重複處理所有的約束行為許多次。建議的重複次數是十次。你可以調整這個數字到你喜歡的,只是要注意,這是速度與準確度的取捨。使用較少的次數會增加速度但是卻會犧牲準確度,相對的,使用較高的次數會減低速度但是也會增加模擬的品質。底下是我們選擇的重複次數。

var iterations:int = 10;

現在我們可以開始模擬了。你可以把模擬的計算合併到影格處理之中。在每次處理時呼叫b2World.step(timeStep, iterations)。根據影格速率與時間間隔,通常只需要呼叫一次就足夠了。

world.Step(timeStep, iterations);


清理

當world離開程式的處理區段(scope),或是刪除(delete)world物件的參考時,所有保留給body物件或是joints物件的記憶體就被釋放了,這是為了讓系統執行更順暢所需的行為。所以你也必需要取消所有body物件與joints物件的參考,因為它們都會變成無效的參考。

沒有留言:

 
Blogger Template Layout Design by [ METAMUSE ] : Code Name Gadget 1.1