怎么樣創建一個box2d的世界。
step.1 :
創建一個世界。
var1 : (gravity:b2Vec2) , 即重力。
var2 : (doSleep:Boolean) , 用來管理世界中的物體是否可以休眠。
step.2 :
創建一個地面,把地面看成一個巨大的四邊形剛體。所以我們現在要做的也相對於創建一個四邊形剛體。
首先創建一個地面的 definition,即b2BodyDef。
_groundDef.position.Set(SWF_HALF_WIDTH/PIXELS_TO_METER,(SWF_HEIGHT-20)/PIXELS_TO_METER);
_groundDef.type = b2Body.b2_staticBody;
b2BodyDef是用來存放剛體在這個世界中的所有數據。
這里要注意一下box2d的特性,1:所有object的注冊點都在中心。2:box2d中的單位是米。
所以如果我們想將地面放置在舞台底部往上20個像素的地方。我們需要這樣處理
_groundDef.position.Set(SWF_HALF_WIDTH/PIXELS_TO_METER,(SWF_HEIGHT-20)/PIXELS_TO_METER);
其中SWF_HALF_WIDTH即舞台寬度的一半,SWF_HEIGHT即舞台高度,PIXEL_TO_METER是一個比例尺,用來描述多少個像素對應1米(一般是30)。
type是剛體類型。分為三種:staticBody , kinematicBody , dynamicBody 。由於地面是靜止的剛體,所以我們給他設置為staticBody。
至於kinematicBody和dynamicBody的區別我們以后再研究。
然后創建地面剛體,即b2Body。
b2Body就是剛體啦。
這里我們可以注意到,box2d采取的是工廠模式。即通過world完成所有創建剛體的工作。
接着我們需要創建這個剛體的形狀,這里我們使用b2PolygonShape。當然還有一些其他的形狀,我們以后再去了解。
_groundBox.SetAsBox(SWF_HALF_WIDTH/PIXELS_TO_METER,20/PIXELS_TO_METER);
b2PolygonShape就是這個剛體的形狀啦。
通常要創建四邊形的話會用到SetAsBox()或者SetAsOrientedBox(),其中后者可以指定注冊點和角度。
另外需要注意的是,在這個方法中傳遞的寬度值和高度值都是半寬和半高。當然還需要轉換到以米為單位。
我們剛才創建的形狀只是這個剛體的definition的一部分。最終我們需要創建的是我們這個地面剛體的definition。
_groundFixtureDef.shape = _groundBox;
_groundFixtureDef.density = 1;
_groundFixtureDef.friction = 1;
_groundFixtureDef.restitution = 0;
_groundBody.CreateFixture(_groundFixtureDef);
b2FixtureDef與之前的b2BodyDef的區別在於。
b2BodyDef是用來存放剛體在世界中的數據,比如position(x,y) , angle 等等屬性。
b2FixtureDef則是用來存放剛體自身的數據,比如shape(polygonShape,等等),density,friction等等屬性。
這樣我們就已經完成了創建地面剛體的整個過程。
接下來我們需要讓他們動起來。
step.3:
private function update(e:Event):void
{
var timeStep: Number = 1 / 30;
var velocityIterations:int = 6;
v ar positionIterations:int = 2;
_world.Step(timeStep,velocityIterations,positionIterations);
_world.ClearForces();
}
我們通過b2World的step方法來刷新整個世界。
step方法要傳遞三個參數,timeStep,velocityIterations, positionIterations。
timeStep,時步。通常建議設置為1/60,這樣的話你的fps最好也設置到60。但是我發現更好的辦法就是把timeStep設置為fps的倒數即可。如果你的fps是30,那么就設置為1/30。
velocityIterations,速度迭代
positionIterations,位置迭代
這兩個值通常建議設置為10,更低的迭代值會讓你犧牲一些准確性,相反的為你的程序提升一部分性能。
另外在box2d version2.1中我們需要清除力。
_world.ClearForces();
step.4:
現在我們嘗試在空中放置一個小小的剛體讓他自由下落。
這跟我們剛才創建地面剛體的做法基本上一致,唯一不同的是需要把剛體的種類設置為dynamicBody。
所以我們把創建四邊形剛體的所有步驟集合在一個方法內。方便反復調用。
private function createBox(position:Point,hw: Number,hh: Number,isDynamic: Boolean,density: Number=0,friction: Number=0,restitution: Number=0):void
{
var bodyDef:b2BodyDef = new b2BodyDef();
if( isDynamic )
{
bodyDef.type = b2Body.b2_kinematicBody.b2_dynamicBody;
}
else
{
bodyDef.type = b2Body.b2_staticBody;
}
bodyDef.position.Set(position.x/PIXELS_TO_METER,position.y/PIXELS_TO_METER);
var body:b2Body = _world.CreateBody(bodyDef);
var shape:b2PolygonShape = new b2PolygonShape();
shape.SetAsBox(hw/PIXELS_TO_METER,hh/PIXELS_TO_METER);
var fixtureDef:b2FixtureDef = new b2FixtureDef();
fixtureDef.shape = shape;
fixtureDef.density = density;
fixtureDef.friction = friction;
fixtureDef.restitution = restitution;
body.CreateFixture(fixtureDef);
}
同時把剛才創建地面剛體的過程通過我們寫好的方法來實現。
這樣我們基本上已經完成了一個世界的搭建。
可是當我們編譯的時候卻看不到任何東西。
什么情況!!
step.5 :
不要急,原來我們剛才創建的世界只是一個虛擬的世界。我們並沒有給他付於實質性的ui,所以我們壓根什么都看不見。
我們現在沒有ui,那該怎么辦呢?
沒關系,box2d已經提供給我們一個debug模式,可以讓我們在沒有ui的時候看到我們的世界。
{
_debugSprite = new Sprite();
addChild(_debugSprite);
_debugDraw = new b2DebugDraw();
_debugDraw.SetSprite(_debugSprite);
_debugDraw.SetDrawScale(PIXELS_TO_METER);
_debugDraw.SetLineThickness(1);
_debugDraw.SetAlpha(1);
_debugDraw.SetFillAlpha(0.4);
_debugDraw.SetFlags(b2DebugDraw.e_shapeBit);
_world.SetDebugDraw(_debugDraw);
}
b2DebugDraw中有一些屬性可以自定義,來改變debug模式的外觀,這個看個人喜好就行啦。
flag可以有以下幾種選擇。如果你想復用的話,這樣即可: b2DebugDraw.e_aabbBit | b2DebugDraw.e_jointBit
b2DebugDraw.e_aabbBit :表示顯示剛體的邊界盒
b2DebugDraw.e_jointBit :表示顯示剛體相連時的節點和連線
b2DebugDraw.e_obbBit :顯示凸多邊形的邊界,不顯示圓的邊界
b2DebugDraw.e_pairBit:draw broad-phase pairs
b2DebugDraw.e_coreShapeBit:draw core (TOI) shapes
b2DebugDraw.e_shapeBit:顯示剛體的形狀,不管是何種形狀
b2DebugDraw.e_centerOfMassBit:顯示重心
另外還需要在幀監聽中添加語句
編譯一下。
OK,大功告成~
附源碼:
2 {
3 import Box2D.Collision.Shapes.b2PolygonShape;
4 import Box2D.Common.Math.b2Vec2;
5 import Box2D.Dynamics.b2Body;
6 import Box2D.Dynamics.b2BodyDef;
7 import Box2D.Dynamics.b2DebugDraw;
8 import Box2D.Dynamics.b2FixtureDef;
9 import Box2D.Dynamics.b2World;
10
11 import flash.display.Sprite;
12 import flash.events.Event;
13 import flash.geom.Point;
14
15 [SWF(frameRate=60,width=800,height=600)]
16 public class Box2dClass_1 extends Sprite
17 {
18 private const PIXELS_TO_METER:int = 30;
19 private const SWF_WIDTH:int = 800;
20 private const SWF_HEIGHT:int = 600;
21 private const SWF_HALF_WIDTH:int = SWF_WIDTH>>1;
22 private const SWF_HALF_HEIGHT:int = SWF_HEIGHT>>1;
23
24 private var _world:b2World;
25 private var _groundDef:b2BodyDef;
26 private var _groundBody:b2Body;
27 private var _groundBox:b2PolygonShape;
28 private var _groundFixtureDef:b2FixtureDef;
29 private var _debugSprite:Sprite;
30 private var _debugDraw:b2DebugDraw;
31
32 public function Box2dClass_1()
33 {
34 stage.color = 0x333333;
35 createWorld();
36 createGround();
38 createBox(new Point(SWF_HALF_WIDTH, 4), 10, 10, true, 1, 0.3);
39 createDebug();
40 stage.addEventListener(Event.ENTER_FRAME, update);
41 }
42
43 private function createWorld():void
44 {
45 _world = new b2World(new b2Vec2(0,10), true );
46 }
47
48 private function createDebug():void
49 {
50 _debugSprite = new Sprite();
51 addChild(_debugSprite);
52
53 _debugDraw = new b2DebugDraw();
54 _debugDraw.SetSprite(_debugSprite);
55 _debugDraw.SetDrawScale(PIXELS_TO_METER);
56 _debugDraw.SetLineThickness(1);
57 _debugDraw.SetAlpha(1);
58 _debugDraw.SetFillAlpha(0.4);
59 _debugDraw.SetFlags(b2DebugDraw.e_shapeBit);
60 _world.SetDebugDraw(_debugDraw);
61 }
62
63 private function createGround():void
64 {
65 _groundDef = new b2BodyDef();
66 _groundDef.position.Set(SWF_HALF_WIDTH/PIXELS_TO_METER,(SWF_HEIGHT-20)/PIXELS_TO_METER);
67 _groundDef.type = b2Body.b2_staticBody;
68
69 _groundBody = _world.CreateBody(_groundDef);
70
71 _groundBox = new b2PolygonShape();
72 _groundBox.SetAsBox(SWF_HALF_WIDTH/PIXELS_TO_METER,20/PIXELS_TO_METER);
73
74 _groundFixtureDef = new b2FixtureDef();
75 _groundFixtureDef.shape = _groundBox;
76 _groundFixtureDef.density = 0;
77 _groundFixtureDef.friction = 0;
78 _groundFixtureDef.restitution = 0;
79
80 _groundBody.CreateFixture(_groundFixtureDef);
81 }
82
83 private function createBox(position:Point,hw: Number,hh: Number,isDynamic: Boolean,density: Number=0,friction: Number=0,restitution: Number=0):void
84 {
85 var bodyDef:b2BodyDef = new b2BodyDef();
86 if( isDynamic )
87 {
88 bodyDef.type = b2Body.b2_dynamicBody;
89 }
90 else
91 {
92 bodyDef.type = b2Body.b2_staticBody;
93 }
94 bodyDef.position.Set(position.x/PIXELS_TO_METER,position.y/PIXELS_TO_METER);
95
96 var body:b2Body = _world.CreateBody(bodyDef);
97
98 var shape:b2PolygonShape = new b2PolygonShape();
99 shape.SetAsBox(hw/PIXELS_TO_METER,hh/PIXELS_TO_METER);
100
101 var fixtureDef:b2FixtureDef = new b2FixtureDef();
102 fixtureDef.shape = shape;
103 fixtureDef.density = density;
104 fixtureDef.friction = friction;
105 fixtureDef.restitution = restitution;
106
107 body.CreateFixture(fixtureDef);
108
109 }
110
111 protected function update(event:Event):void
112 {
113 var timeStep: Number = 1 / 30;
114 var velocityIterations:int = 6;
115 var positionIterations:int = 2;
116
117 _world.Step(timeStep,velocityIterations,positionIterations);
118 _world.ClearForces();
119 _world.DrawDebugData();
120 }
121 }
122 }
另附上box2d結構圖一枚:
