[box2d] Box2d学习笔记 - Class.02 - 2012.10.22

上一课中我们了解了如何去创建一个box2d的世界,如果在这个世界中添加刚体,如何通debug模式查看效果。

现在我们来学习一个让人激动的跳起来的酷东西 —— “关节”。

顾名思义,我们可以通过关节来建立各式各样的物理系统,链条、齿轮、绳索、甚至是通过关节来建立一个物理系统,等等。

听起来是不是很激动人心?是的,我们现在马上来看看box2d到底提供了哪些关节类吧:

 

Distance Joint

Rope Joint

Revolute Joint

Prismatic Joint

Pulley Joint

Gear Joint

Line Joint

Weld Joint

Mouse Joint

 

五花八门的关节类让我们眼花缭乱,光看类名也无法完全体会到这些关节类之间的差异。还是通过具体的实现来一个一个看效果吧

 

no.1 , Distance Joint 

距离关节,顾名思义,通过该关节连接的两个刚体之间的距离是恒定不变的。

 

_box1 = createBox(new Point(SWF_HALF_WIDTH, 50), 10, 10, true, 1, 0.3);
_box2 = createBox(new Point(SWF_HALF_WIDTH+50, 50), 10, 10, false, 1, 0.3);
createJoint();

private function createJoint():void
{
  _distanceJointDef = new b2DistanceJointDef();
  _distanceJointDef.Initialize(_box1,_box2,_box1.GetWorldCenter(),_box2.GetWorldCenter());
          
  _world.CreateJoint(_distanceJointDef);
}

 

 

no.2 , Rope Joint

绳索关节,绳索关节跟距离关节非常类似,都是把两个刚体的距离限定为一个距离值,唯一不同的地方在于绳索关节中两个刚体的距离不会被限定成这个距离值,还可以小于他。你可以把Distance Joint想象成一个刚体的绳索,而Rope Joint则是一个可以伸缩的绳索。

 

另外需要注意的是:最新的box2d 2.1a 中似乎已经移除了关于RopeJoint的定义,如果你想要使用它,你可以在这里下载到相关的类:http://blog.allanbishop.com/box2d-2-1a-rope-joint-ported-to-as3/

存放位置为Dynamic\Joints。其中b2Joint.as需要覆盖原先的。

 

_box1 = createBox(new Point(SWF_HALF_WIDTH, 50), 10, 10, true, 1, 0.3);
_box2 = createBox(new Point(SWF_HALF_WIDTH+50, 50), 10, 10, false, 1, 0.3);
createJoint();

private function createJoint():void
{
  _ropeJointDef = new b2RopeJointDef();
  _ropeJointDef.bodyA = _box1;
  _ropeJointDef.bodyB = _box2;
  _ropeJointDef.localAnchorA = new b2Vec2(0,0);
  _ropeJointDef.localAnchorB = new b2Vec2(0,0);
  _ropeJointDef.maxLength = 100/PIXELS_TO_METER;
  _ropeJointDef.collideConnected = true;
  _world.CreateJoint(_ropeJointDef);          
}

 


no.3 Revolute Joint

转动关节,这是一个非常实用的关节类。当我们通过这个关节连接的两个刚体中有一个staticBody,有一个是dynamicBody时,dynamicBody会绕着staticBody进行旋转,就好像把一张纸钉在墙上。两个dynamic bodies也可以通过它来连接,那么这两个刚体就会互相旋转。此外,你还可以对它们设置扭矩。

 

_box1 = createBox(new Point(SWF_HALF_WIDTH, 50), 10, 10, true, 1, 0.3);
_box2 = createBox(new Point(SWF_HALF_WIDTH+50, 50), 10, 10, false, 1, 0.3);
createJoint();
            
private function createJoint():void
{
  _revoluteJointDef = new b2RevoluteJointDef();
  _revoluteJointDef.Initialize(_box1,_box2,_box2.GetWorldCenter());
  _revoluteJointDef.maxMotorTorque = 1;
  _revoluteJointDef.enableMotor = true;
  _world.CreateJoint(_revoluteJointDef);
}

 


no.4 Prismatic Joint 

移动关节,允许两个刚体沿着某个轴相对移动,类似于传送带。需要注意的是移动关节阻止相对旋转。

 

_box1 = createBox(new Point(SWF_HALF_WIDTH, SWF_HEIGHT-50), 10, 10, true, 1, 0.3);
createJoint();             
            
private function createJoint():void
{
  _prismaticJointDef = new b2PrismaticJointDef();
  _prismaticJointDef.Initialize(_box1,_groundBody,_box1.GetWorldCenter(),new b2Vec2(1,0));
  _prismaticJointDef.lowerTranslation = -5;
  _prismaticJointDef.upperTranslation = 5;
  _prismaticJointDef.enableLimit = true;
  _prismaticJointDef.maxMotorForce = 1;
  _prismaticJointDef.motorSpeed = 1;
  _prismaticJointDef.enableMotor = true;
            
  _world.CreateJoint(_prismaticJointDef);
}    

 

 

no.5 Pulley Joint

滑轮关节,两个刚体被连接起来,当一个落下,另一个物体便抬起来。你可以通过设置一个ratio值来决定两段距离之间的换算关系。

_box1 = createBox(new Point(SWF_HALF_WIDTH, 150), 10, 10, true, 1, 0.3);
_box2 = createBox(new Point(SWF_HALF_WIDTH+50, 150), 10, 10, true, 1, 0.3);
createJoint();
      
private function createJoint():void
{
  var anchor1:b2Vec2 = _box1.GetWorldCenter();
  var anchor2:b2Vec2 = _box2.GetWorldCenter();
            
  var groundAnchor1:b2Vec2 = new b2Vec2(anchor1.x,anchor1.y-100/PIXELS_TO_METER);
  var groundAnchor2:b2Vec2 = new b2Vec2(anchor2.x , anchor2.y - 100/PIXELS_TO_METER);
  var ratio:Number = 1;
    
  _pullyJointDef = new b2PulleyJointDef();
  _pullyJointDef.Initialize(_box1,_box2,groundAnchor1,groundAnchor2,anchor1,anchor2,ratio);
  _pullyJointDef.maxLengthA = 150/PIXELS_TO_METER;
  _pullyJointDef.maxLengthB = 150/PIXELS_TO_METER;
            
  _world.CreateJoint(_pullyJointDef);
}    


no.6 Gear Joint

齿轮关节,齿轮关节需要两个刚体通过旋转关节或者平移关节连接起来。同样的,你也可以给他设定ratio值。

_box1 = createBox(new Point(SWF_HALF_WIDTH, 150), 10, 10, true, 1, 0.3);
_box2 = createBox(new Point(SWF_HALF_WIDTH+50, 200), 10, 10, true, 1, 0.3);
createJoint();

private function createJoint():void
{
  _revoluteJointDef = new b2RevoluteJointDef();
  _revoluteJointDef.Initialize(_groundBody,_box1,_box1.GetWorldCenter());
  _revoluteJointDef.lowerAngle = -5 * b2Settings.b2_pi;
  _revoluteJointDef.upperAngle = 5 * b2Settings.b2_pi;
  _revoluteJointDef.enableLimit = true;
  _revoluteJointDef.maxMotorTorque = 10;
  _revoluteJointDef.motorSpeed = 1;
  _revoluteJointDef.enableMotor = true;
            
  _revoluteJoint = _world.CreateJoint(_revoluteJointDef) as b2RevoluteJoint;
            
  _prismaticJointDef = new b2PrismaticJointDef();
  _prismaticJointDef.Initialize(_groundBody,_box2,_box2.GetWorldCenter(),new b2Vec2(1,0));
  _prismaticJointDef.lowerTranslation = -50;
  _prismaticJointDef.upperTranslation = 50;
  _prismaticJointDef.enableLimit = true;
  _prismaticJointDef.maxMotorForce = 1;
  _prismaticJointDef.motorSpeed = 1;
  _prismaticJointDef.enableMotor = true;
            
  _prismaticJoint = _world.CreateJoint(_prismaticJointDef) as b2PrismaticJoint;
            
  _gearJointDef = new b2GearJointDef();
  _gearJointDef.joint1 = _revoluteJoint;
  _gearJointDef.joint2 = _prismaticJoint;
  _gearJointDef.bodyA = _box1;
  _gearJointDef.bodyB = _box2;
  _gearJointDef.ratio = 2*b2Settings.b2_pi;
            
  _world.CreateJoint(_gearJointDef);  

       

no.7 Line Joint

线性关节,跟移动关节类似,但没有旋转方面的约束。一般都用来模拟汽车的车轮。

_box1 = createBox(new Point(SWF_HALF_WIDTH, SWF_HEIGHT-50), 10, 10, true, 1, 0.3);

createJoint();


            
private function createJoint():void
{
  _lineJointDef = new b2LineJointDef();
  _lineJointDef.Initialize(_groundBody,_box1,_box1.GetWorldCenter(),new b2Vec2(1,0));
  _lineJointDef.lowerTranslation = -5;
  _lineJointDef.upperTranslation = 5;
  _lineJointDef.enableLimit = true;
  _lineJointDef.maxMotorForce = 10;
  _lineJointDef.motorSpeed = 10;
  _lineJointDef.enableMotor = true;
            
  _world.CreateJoint(_lineJointDef); 

 

no.8 Weld Joint

焊接节点,这个最容易了。。就是把两个刚体焊接在一起,可以用来创建各种结构。

_box1 = createBox(new Point(SWF_HALF_WIDTH, 200), 10, 10, true, 1, 0.3);
_box2 = createBox(new Point(SWF_HALF_WIDTH+50, 200), 10, 10, true, 1, 0.3);

createJoint();

private function createJoint():void

{
  _weldJointDef = new b2WeldJointDef();
  _weldJointDef.Initialize(_box1,_box2,_box1.GetWorldCenter());

  _world.CreateJoint(_weldJointDef);
}        

 

no.9 Mouse Joint

鼠标节点,顾名思义,用来和box2d世界做鼠标交互的节点。我们马上来看看怎么用~

这同时也是九个节点中最复杂的。

 

首先创建监听

_box1 = createBox(new Point(SWF_HALF_WIDTH, 200), 10, 10, true, 1, 0.3);
_box2 = createBox(new Point(SWF_HALF_WIDTH+50, 200), 10, 10, true, 1, 0.3);

stage.addEventListener(MouseEvent.MOUSE_DOWN , onDragHandler); 

 

stage.addEventListener(MouseEvent.MOUSE_UP , onDropHandler);             

 

 

监听函数

var _mousePVec:b2Vec2 = new b2Vec2();


protected function onDragHandler(event:MouseEvent):void
{
  var body:b2Body = getBodyAtMouse();        
  if( body )
  {
    _mouseJointDef = new b2MouseJointDef();
    _mouseJointDef.bodyA = _world.GetGroundBody();
    _mouseJointDef.bodyB = body;
    _mouseJointDef.target.Set(mouseX/PIXELS_TO_METER,mouseY/PIXELS_TO_METER);
    _mouseJointDef.maxForce = 3000;
    _mouseJoint = _world.CreateJoint(_mouseJointDef) as b2MouseJoint;
  }
}
    
protected function onDropHandler(event:MouseEvent):void
{
  if(_mouseJoint)

  {

     _world.DestroyJoint(_mouseJoint);
     _mouseJoint = null;
  }
}
 
private function getBodyAtMouse(includeStatic:Boolean=false):b2Body
{            
  var mouseXWorldPhys:Number = mouseX/PIXELS_TO_METER;
  var mouseYWorldPhys:Number = mouseY/PIXELS_TO_METER;
  _mousePVec.Set(mouseXWorldPhys,mouseYWorldPhys);
  var aabb:b2AABB = new b2AABB();
  aabb.lowerBound.Set(mouseXWorldPhys-0.001,mouseXWorldPhys+0.001);
  aabb.upperBound.Set(mouseYWorldPhys-0.001,mouseYWorldPhys+0.001);
  var body:b2Body = null;
  var fixture:b2Fixture ;
            
  function GetBodyCallBack(fixture:b2Fixture):Boolean
  {
    var shape:b2Shape = fixture.GetShape();
    if( fixture.GetBody().GetType() != b2Body.b2_staticBody || includeStatic )
    {
      var inside:Boolean = shape.TestPoint(fixture.GetBody().GetTransform(),_mousePVec);
      if( inside )
      {
        body = fixture.GetBody();
        return false;
      }
    }    
    return true;
  }
            
  world.QueryAABB(GetBodyCallBack,aabb);
  return body;  

 

刷新函数

 

protected function update(event:Event):void
{
  var timeStep:Number = 1 / 30;
  var velocityIterations:int = 6;
  var positionIterations:int = 2;
            
  if(_mouseJoint)
  {
    var xpos:Number = mouseX/PIXELS_TO_METER;
    var ypos:Number = mouseY/PIXELS_TO_METER;
    var v2:b2Vec2 = new b2Vec2(xpos,ypos);
    _mouseJoint.SetTarget(v2);
  }
            
  _world.Step(timeStep,velocityIterations,positionIterations);
  _world.ClearForces();
  _world.DrawDebugData();
}

 

OK,大功告成,你可以把你的小盒子扔来扔去了……

这次我们只是大致了解了这些节点,接下来我们要更加深入的去了解和熟悉他们。

 

附上鼠标节点的源码: 

 

  1 package
  2 {
  3     import Box2D.Collision.Shapes.b2PolygonShape;
  4     import Box2D.Collision.Shapes.b2Shape;
  5     import Box2D.Collision.b2AABB;
  6     import Box2D.Common.Math.b2Vec2;
  7     import Box2D.Common.b2Settings;
  8     import Box2D.Dynamics.Joints.b2DistanceJointDef;
  9     import Box2D.Dynamics.Joints.b2GearJointDef;
 10     import Box2D.Dynamics.Joints.b2Joint;
 11     import Box2D.Dynamics.Joints.b2LineJointDef;
 12     import Box2D.Dynamics.Joints.b2MouseJoint;
 13     import Box2D.Dynamics.Joints.b2MouseJointDef;
 14     import Box2D.Dynamics.Joints.b2PrismaticJoint;
 15     import Box2D.Dynamics.Joints.b2PrismaticJointDef;
 16     import Box2D.Dynamics.Joints.b2PulleyJointDef;
 17     import Box2D.Dynamics.Joints.b2RevoluteJoint;
 18     import Box2D.Dynamics.Joints.b2RevoluteJointDef;
 19     import Box2D.Dynamics.Joints.b2RopeJointDef;
 20     import Box2D.Dynamics.b2Body;
 21     import Box2D.Dynamics.b2BodyDef;
 22     import Box2D.Dynamics.b2DebugDraw;
 23     import Box2D.Dynamics.b2Fixture;
 24     import Box2D.Dynamics.b2FixtureDef;
 25     import Box2D.Dynamics.b2World;
 26     
 27     import flash.display.Sprite;
 28     import flash.events.Event;
 29     import flash.events.MouseEvent;
 30     import flash.geom.Point;
 31     
 32     [SWF(frameRate=60,width=800,height=600)]
 33     public class Box2dClass_2 extends Sprite
 34     {
 35         private const PIXELS_TO_METER:int = 30;
 36         private const SWF_WIDTH:int = 800;
 37         private const SWF_HEIGHT:int = 600; 
 38         private const SWF_HALF_WIDTH:int = SWF_WIDTH>>1;
 39         private const SWF_HALF_HEIGHT:int = SWF_HEIGHT>>1;
 40         
 41         private var _world:b2World;
 42         private var _groundDef:b2BodyDef;
 43         private var _groundBody:b2Body;
 44         private var _groundBox:b2PolygonShape;
 45         private var _groundFixtureDef:b2FixtureDef;
 46         private var _debugSprite:Sprite;
 47         private var _debugDraw:b2DebugDraw;
 48         
 49         private var _box1:b2Body;
 50         private var _box2:b2Body;
 51         private var _distanceJointDef:b2DistanceJointDef;
 52         private var _box3:b2Body;
 53         private var _ropeJointDef:b2RopeJointDef;
 54         private var _revoluteJointDef:b2RevoluteJointDef;
 55         private var _prismaticJointDef:b2PrismaticJointDef;
 56         private var _pullyJointDef:b2PulleyJointDef;
 57         private var _revoluteJoint:b2RevoluteJoint;
 58         private var _gearJointDef:b2GearJointDef;
 59         private var _prismaticJoint:b2Joint;
 60         private var _lineJointDef:b2LineJointDef;
 61         
 62         private var _mousePVec:b2Vec2 = new b2Vec2();
 63         private var _mouseJointDef:b2MouseJointDef;
 64         private var _mouseJoint:b2MouseJoint;
 65         
 66         public function Box2dClass_2()
 67         {
 68             stage.color = 0x333333;
 69             createWorld();
 70             createDebug();
 71             createGround();
 72             _box1 = createBox(new Point(SWF_HALF_WIDTH, 200), 10, 10, true, 1, 0.3);
 73             _box2 = createBox(new Point(SWF_HALF_WIDTH+50, 200), 10, 10, true, 1, 0.3);
 74             createJoint();
 75             
 76             stage.addEventListener(Event.ENTER_FRAME, update);
 77             stage.addEventListener(MouseEvent.MOUSE_DOWN , onDragHandler);
 78             stage.addEventListener(MouseEvent.MOUSE_UP , onDropHandler);
 79         }
 80         
 81         protected function onDragHandler(event:MouseEvent):void
 82         {
 83             var body:b2Body = getBodyAtMouse();        
 84             if( body )
 85             {
 86                 _mouseJointDef = new b2MouseJointDef();
 87                 _mouseJointDef.bodyA = _world.GetGroundBody();
 88                 _mouseJointDef.bodyB = body;
 89                 _mouseJointDef.target.Set(mouseX/PIXELS_TO_METER,mouseY/PIXELS_TO_METER);
 90                 _mouseJointDef.maxForce = 3000;
 91                 _mouseJoint = _world.CreateJoint(_mouseJointDef) as b2MouseJoint;
 92             }
 93         }
 94         
 95         protected function onDropHandler(event:MouseEvent):void
 96         {
 97             if(_mouseJoint){
 98                 _world.DestroyJoint(_mouseJoint);
 99                 _mouseJoint = null;
100             }
101         }
102         
103         private function getBodyAtMouse(includeStatic:Boolean=false):b2Body
104         {            
105             var mouseXWorldPhys:Number = mouseX/PIXELS_TO_METER;
106             var mouseYWorldPhys:Number = mouseY/PIXELS_TO_METER;
107             _mousePVec.Set(mouseXWorldPhys,mouseYWorldPhys);
108             var aabb:b2AABB = new b2AABB();
109             aabb.lowerBound.Set(mouseXWorldPhys-0.001,mouseXWorldPhys+0.001);
110             aabb.upperBound.Set(mouseYWorldPhys-0.001,mouseYWorldPhys+0.001);
111             var body:b2Body = null;
112             var fixture:b2Fixture ;
113             
114             function GetBodyCallBack(fixture:b2Fixture):Boolean
115             {
116                 
117                 var shape:b2Shape = fixture.GetShape();
118                 if( fixture.GetBody().GetType() != b2Body.b2_staticBody || includeStatic )
119                 {
120                     var inside:Boolean = shape.TestPoint(fixture.GetBody().GetTransform(),_mousePVec);
121                     if( inside )
122                     {
123                         body = fixture.GetBody();
124                         return false;
125                     }
126                 }    
127                 return true;
128             }
129             
130             _world.QueryAABB(GetBodyCallBack,aabb);
131             return body;
132         }
133         
134         private function createJoint():void
135         {
136             
137         }
138         
139         private function createWorld():void
140         {
141             _world = new b2World(new b2Vec2(0,10),true );    
142         }
143         
144         private function createDebug():void
145         {
146             _debugSprite = new Sprite();
147             addChild(_debugSprite);
148             
149             _debugDraw = new b2DebugDraw();
150             _debugDraw.SetSprite(_debugSprite);
151             _debugDraw.SetDrawScale(PIXELS_TO_METER);
152             _debugDraw.SetLineThickness(1);
153             _debugDraw.SetAlpha(1);
154             _debugDraw.SetFillAlpha(0.4);
155             _debugDraw.SetFlags(b2DebugDraw.e_shapeBit);
156             _world.SetDebugDraw(_debugDraw);
157         }
158         
159         private function createGround():void
160         {
161             _groundDef = new b2BodyDef();
162             _groundDef.position.Set(SWF_HALF_WIDTH/PIXELS_TO_METER,(SWF_HEIGHT-20)/PIXELS_TO_METER);
163             _groundDef.type = b2Body.b2_staticBody;
164             
165             _groundBody = _world.CreateBody(_groundDef); 
166             
167             _groundBox = new b2PolygonShape();
168             _groundBox.SetAsBox(SWF_HALF_WIDTH/PIXELS_TO_METER,20/PIXELS_TO_METER);
169             
170             _groundFixtureDef = new b2FixtureDef();
171             _groundFixtureDef.shape = _groundBox;
172             _groundFixtureDef.density = 0;
173             _groundFixtureDef.friction = 0;
174             _groundFixtureDef.restitution = 0;
175             
176             _groundBody.CreateFixture(_groundFixtureDef);
177         }
178         
179         private function createBox(position:Point,hw:Number,hh:Number,isDynamic:Boolean,density:Number=0,friction:Number=0,restitution:Number=0):b2Body
180         {
181             var bodyDef:b2BodyDef = new b2BodyDef();
182             if( isDynamic )
183             {
184                 bodyDef.type = b2Body.b2_dynamicBody;
185             }
186             else
187             {
188                 bodyDef.type = b2Body.b2_staticBody;
189             }
190             bodyDef.position.Set(position.x/PIXELS_TO_METER,position.y/PIXELS_TO_METER);
191             
192             var body:b2Body = _world.CreateBody(bodyDef);
193             
194             var shape:b2PolygonShape = new b2PolygonShape();
195             shape.SetAsBox(hw/PIXELS_TO_METER,hh/PIXELS_TO_METER);
196             
197             var fixtureDef:b2FixtureDef = new b2FixtureDef();
198             fixtureDef.shape = shape;
199             fixtureDef.density = density;
200             fixtureDef.friction = friction;
201             fixtureDef.restitution = restitution;
202             
203             body.CreateFixture(fixtureDef);
204             
205             return body;
206         }
207         
208         protected function update(event:Event):void
209         {
210             var timeStep:Number = 1 / 30;
211             var velocityIterations:int = 6;
212             var positionIterations:int = 2;
213             
214             if(_mouseJoint)
215             {
216                 var xpos:Number = mouseX/PIXELS_TO_METER;
217                 var ypos:Number = mouseY/PIXELS_TO_METER;
218                 var v2:b2Vec2 = new b2Vec2(xpos,ypos);
219                 _mouseJoint.SetTarget(v2);
220             }
221             
222             _world.Step(timeStep,velocityIterations,positionIterations);
223             _world.ClearForces();
224             _world.DrawDebugData();
225         }
226     }
227 }

 

 

 

posted @ 2012-10-22 02:59  Memo  阅读(2844)  评论(0编辑  收藏  举报