[box2d] Box2d學習筆記 - Class.01 - 2012.10.5


怎么樣創建一個box2d的世界。


step.1 :  

 

創建一個世界。 

 

var  world:b2World = new World( new b2Vec2(0,10) ,  true  );

 

var1 : (gravity:b2Vec2) , 即重力。

var2 : (doSleep:Boolean) , 用來管理世界中的物體是否可以休眠。

 

step.2 :

 

創建一個地面,把地面看成一個巨大的四邊形剛體。所以我們現在要做的也相對於創建一個四邊形剛體。

 

首先創建一個地面的 definition,即b2BodyDef。
var  _groundDef:b2BodyDef = new 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。

var _groundBody:b2Body = _world.CreateBody(_groundDef);

b2Body就是剛體啦。

這里我們可以注意到,box2d采取的是工廠模式。即通過world完成所有創建剛體的工作。

 

接着我們需要創建這個剛體的形狀,這里我們使用b2PolygonShape。當然還有一些其他的形狀,我們以后再去了解。

var _groundBox = new b2PolygonShape();
_groundBox.SetAsBox(SWF_HALF_WIDTH/PIXELS_TO_METER,20/PIXELS_TO_METER);

b2PolygonShape就是這個剛體的形狀啦。

通常要創建四邊形的話會用到SetAsBox()或者SetAsOrientedBox(),其中后者可以指定注冊點和角度。

另外需要注意的是,在這個方法中傳遞的寬度值和高度值都是半寬和半高。當然還需要轉換到以米為單位。

 

我們剛才創建的形狀只是這個剛體的definition的一部分。最終我們需要創建的是我們這個地面剛體的definition。

var _groundFixtureDef:b2FixtureDef = new b2FixtureDef();
_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:

stage.addEventListener(Event.ENTER_FRAME, update);

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。 

所以我們把創建四邊形剛體的所有步驟集合在一個方法內。方便反復調用。

createBox(new Point(SWF_HALF_WIDTH, 4), 30, 30,  true, 1, 0.3);       

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);


同時把剛才創建地面剛體的過程通過我們寫好的方法來實現。

createBox(new Point(SWF_HALF_WIDTH, SWF_HEIGHT - 20), SWF_HALF_WIDTH, 20,  false, 1, 1);


這樣我們基本上已經完成了一個世界的搭建。

可是當我們編譯的時候卻看不到任何東西。

什么情況!!

 

step.5 :

不要急,原來我們剛才創建的世界只是一個虛擬的世界。我們並沒有給他付於實質性的ui,所以我們壓根什么都看不見。

我們現在沒有ui,那該怎么辦呢?

沒關系,box2d已經提供給我們一個debug模式,可以讓我們在沒有ui的時候看到我們的世界。

private  function createDebug():void
{
  _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:顯示重心

 

另外還需要在幀監聽中添加語句

 

_world.DrawDebugData(); 

 


編譯一下。 

OK,大功告成~

 

附源碼:

 

  1 package
  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結構圖一枚: 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM