[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;
  var 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结构图一枚: 

 

 

posted @ 2012-10-05 18:24  Memo  阅读(4677)  评论(2编辑  收藏  举报