掉落的苹果——b2Body刚体
上一节中,我们认识了Box2D世界,学习了它的创建方法。今天我们一起来扮演牛顿,认识一下Box2D世界中掉落的苹果。在开始之前,我们想先说明两个内容:
1. Box2D中的计量单位是米
在Box2D中的计量单位是米m,而不是Flash中的像素px,在布置坐标时,要进行一个转换,1米=30个像素。所以Box2D中(a,b)点对于Flash中的(a*30,b*30)的位置,或者说Flash中的(c,d)位置对应Box2D中的(c/30,d/30)位置。
2. Box2D用b2DebugDraw进行模拟调试
Box2D是一个物理引擎,不会向Flash显示列表中添加任何显示对象。不过Box2D中有一个b2DebugDraw类,可以绑定一个显示对象,进行模拟调试。至于如何在Box2D中添加显示对象,在以后的学习中,我们再深入讨论。
b2DebugDraw的用法:
- 创建一个空的Sprite对象debugSprite,并添加到舞台中
- 创建一个b2DebugDraw对象debugDraw,并设置它的m_sprite属性值为debugSprite.
- 用world的SetDebugDraw方法,绑定debugDraw
3. World的更新:
Box2D的和Flash一样,需要实时更新,Flash中有ENTER_FRAME,b2world有step,其参数一表示模拟的时长,二表示限制碰撞后检测程式运行的次数,防止死循环。
刚体与DisplayObject的区别
掉落的苹果实际上是Box2D里的一个刚体b2Body,当然可以把他理解成Flash中的sprite,不过:
A. b2Body
1. 它是Box2D中的一个物理模拟对象,不是可显示对象,但是可以通过b2DebugDraw来进行调试模拟
2. 它的计量单位是米m
3. 它通过b2World.createBody()来创建
B. Sprite
1. 它是显示对象,通过addChild添加即可显示
2. 它的计量单位是像素px
3. 通过new来创建,然后addChild添加后直接显示在舞台上
刚体创建的过程,与AS中new一个对象,addChild到舞台中显示比起来要复杂很多,刚体的创建可以看做是一个工厂模式,根据你的需求(b2BodyDef)生产指定的刚体
刚体的创建过程可以分为两个步骤:
1. 创建刚体需求b2BodyDef。
var bodyRequest:b2BodyDef = new b2BodyDef();
在这个需求中,我们可以包括下面的内容:
a) position:刚体的坐标位置,单位是米m
b) angle:刚体的角度
c) 其他,在以后的学习中我们会陆续介绍
2. b2World工厂用createBody方法创建刚体产品,并自动将其添加到Box2D世界中,然后返回该刚体。
body=world.CreateBody(bodyRequest);
定义刚体形状
到目前位置,我们已经成功添加了一个刚体。
讲个题外话,今天我同时的老婆生了,听到这个消息,你会问的第一个问题是什么?”男孩,女孩?”答对了!
把刚体当成我们的孩子吧。创建一个刚体后,你应该问什么?”方的,圆的?”(这孩子好挫啊!)非常正确。刚体的形状不是与生俱来的,需要用一个b2Shape的子类对象指定。刚体形状的创建过程同样也是一个工厂模式。
这个创建过程与b2Body的创建过程是一样的。我们的形状需求b2ShapeDef可以报考下面的内容:
a) density:质量
b) friction:表面摩擦力
c) restitution:表面张力,这个值越大,刚体越硬
d) SetAsBox:设置刚体为矩形
e) 其他,在以后的学习中我们会陆续介绍
好了创建b2Body刚体的完整过程就讲完了。我们在总结一下:
1. 创建刚体需求b2BodyDef
2. Box2D世界工厂根据需求用createBody方法创建刚体
3. 创建刚体形状需求b2ShapeDef的子类对象
4. B2Body工厂根据需求用createShape方法创建形状
实例练习
掌握了上面的内容,我相信完成下面的这个练习就不是什么难事了。
点击舞台的任意位置创建一个方形刚体。
代码
package { import Box2D.Collision.b2AABB; import Box2D.Collision.Shapes.b2PolygonDef; import Box2D.Common.Math.b2Vec2; import Box2D.Dynamics.b2Body; import Box2D.Dynamics.b2BodyDef; import Box2D.Dynamics.b2DebugDraw; import Box2D.Dynamics.b2World; import flash.display.Sprite; import flash.events.Event; import flash.events.MouseEvent; /** * http://www.ladeng6666.com * @author ladeng6666 */ public class Main extends Sprite { private var world:b2World; private var body:b2Body; public function Main() { createWorld(); createDebug(); createBody(stage.stageWidth/2,0); createGround(); addEventListener(Event.ENTER_FRAME, loop); stage.addEventListener(MouseEvent.MOUSE_DOWN, onStageMouseDown); } private function onStageMouseDown(e:MouseEvent):void { createBody(mouseX,mouseY); } private function loop(e:Event):void { world.Step(1/30, 10); } private function createWorld():void { //1.创建一个环境 var environment:b2AABB = new b2AABB(); environment.lowerBound = new b2Vec2( -100, -100); environment.upperBound = new b2Vec2(100, 100); //2.声明重力 var gravity:b2Vec2 = new b2Vec2(0, 10); //3.睡着的对象是否模拟 var doSleep:Boolean = true; //4.创建b2World世界 world = new b2World(environment, gravity, doSleep); } private function createDebug():void { var debugSprite:Sprite = new Sprite(); addChild(debugSprite); var debugDraw:b2DebugDraw = new b2DebugDraw(); debugDraw.m_sprite = debugSprite; debugDraw.m_drawScale = 30.0; debugDraw.m_fillAlpha = 0.5; debugDraw.m_lineThickness = 1.0; debugDraw.m_drawFlags = b2DebugDraw.e_shapeBit | b2DebugDraw.e_jointBit; world.SetDebugDraw(debugDraw); } private function createBody(posX:Number,posY:Number):void { //1.创建刚体需求b2BodyDef var bodyRequest:b2BodyDef = new b2BodyDef(); bodyRequest.position.Set(posX / 30, posY / 30);//记得米和像素的转换关系 //2.Box2D世界工厂更具需求创建createBody()生产刚体 body=world.CreateBody(bodyRequest); //3.创建敢提形状需求b2ShapeDef的子类 var shapeRequest:b2PolygonDef = new b2PolygonDef(); //详细说明我们的需求 shapeRequest.density = 3; shapeRequest.friction = 0.3; shapeRequest.restitution = 0.2; shapeRequest.SetAsBox(1, 1); //4.b2Body刚体工厂根据需求createShape生产形状 body.CreateShape(shapeRequest); body.SetMassFromShapes(); } private function createGround():void { //1.创建刚体需求b2BodyDef var bodyRequest:b2BodyDef = new b2BodyDef(); bodyRequest.position.Set(stage.stageWidth/2 / 30, stage.stageHeight/30);//记得米和像素的转换关系 //2.Box2D世界工厂更具需求创建createBody()生产刚体 body=world.CreateBody(bodyRequest); //3.创建敢提形状需求b2ShapeDef的子类 var shapeRequest:b2PolygonDef = new b2PolygonDef(); //详细说明我们的需求 shapeRequest.density = 0; shapeRequest.friction = 0.3; shapeRequest.restitution = 0.2; shapeRequest.SetAsBox(stage.stageWidth/30, 1); //4.b2Body刚体工厂根据需求createShape生产形状 body.CreateShape(shapeRequest); body.SetMassFromShapes(); } } }
联系作者
很好的教程,学习了,谢谢拉登兄
谢谢你的关注,我会努力写出更多教程的!
我下的这个box2d2.1a怎么没有b2PolygonDef这个类啊
在box2d2.1a中貌似都统一成了b2FixtureDef,你搜索一下啊
2. b2World工厂用createBody方法创建刚体产品,并自动将其添加到Box2D世界中,然后返回该刚体。
body = world.CreateBody(bodyRequest);
你这个body是什么啊 也没定义啊
这里的body是全局变量,在顶部定义的。
喜欢你的博客
我不明白
body在这里只是一个工厂的概念吗?
如果说每个刚体有一个对应的对象,那对应的对象是bodyRequest吗?
还有createDebug()应该是控制刚体显示的,但是我看不出来那句话显示了所有刚体啊
不好意思啊,我菜鸟,才学as一个月,然后上网看到有引擎,所以好奇想学。
其实我就是想知道愤怒的小鸟这种游戏,小鸟是一个sprite,但是我怎么让这个小鸟变成一个刚体呢?
相信你看过刚体的上衣就知道怎么做了
createDebug是我自定义的一个函数,实际上绘制刚体对象的是b2DebugDraw类。
你可以把b2BodyDef和b2PolygonDef看成是body必备元素,你所说的对应的对象是只的body.useData,这个属性用来绑定一个显示对象。
谢谢,欢迎你继续关注我的博客
你好,我想请问一下,那个红色的矩形区域可以被隐藏掉么?
你指的是不显示吗?如果是的话,那不绘制b2DebugDraw就可以啦,但是这时候必须要设置body的userdata,具体请参考刚体的上衣——b2BodyDef.userData
你好,拉登兄学习BOX2D有去看懂引擎的代码吗?
不用去了解引擎的代码,只要会用就可以,当然如果你用起来易如反掌,可以研究并升级Box2D源代码,呵呵!
拉登兄你好,请教你一个问题,引擎中的密度到底有什么作用?我分别将同等大小的2个下落的小球的密度设置为不同的值,可是它们的下落速度还是一样..如果我要实现同样大小尺寸的2个物理同时下落,但要求这2个物体的下落速度不一样该怎么做?谢谢,请你务必回答我这2个问题,再次感谢!!
Box2D模拟的是一个真空的环境,记得阿基米德的一个小球和羽毛同时落地吗?下落的速度和质量是没有关系的。如果想让物体下落速度快,可以通过ApplyForce对物体再施加一个向下的速度,具体ApplyForce的用法请参考让刚体听我的——ApplyForce、ApplyImpulse、SetLinearVelocity
感谢拉登兄的回复!!
只是有一点我还不太明白,就是引擎中物体的密度到底有什么作用?它究竟能改变物体的什么?请再回答我这一个问题,再次感谢!!
密度会影响物体的质量,质量越大,物体的惯性越大,因此物体的动量维持的就越久。
简单的讲,相同体积的静止的刚体上施加相同的力,密度大的移动的较慢,密度小的移动的较快。
同样的道理,以相同速度移动的同体积刚体,密度小的停下来的比较早,而密度大的物体停下的较晚。
不知道,我这么解释你能听明白吗?
非常感谢!
谢谢你的关注!!
private function createBody(posX:Number,posY:Number):void
private function createGround():void
这两个写鼠标的那个就行了,上来就创建一个刚体虽然设计上没问题,但是以新手的角度来解读的话,他会以为你的最后一句有另外的含义,起始,只不过就是创建一个刚体而已,没有太对必要的!
大师哥,我知道错了,以后会注意的!!
建议把debugDraw等等中文翻译成中文,初学者难懂啊,我觉得比flash里面的类名难懂多了
debugDraw等中文翻译成中文?你的意思讲一下debugDraw的用法嘛?
不,就是debugDraw等的在这个引擎里面最确切的中文字面意思,不是它的用法
我想问一下你这代码是在什么环境下写的,是flash cs还是flash developer
拉登大哥,除了debugDraw其他的都看懂了,谢谢你提供这个好教程,
请你讲解一下debugDraw的作用,用法,和程序逻辑,最好打个比喻,好理解,
万分感谢
Box2D只是一个2D物理引擎,它通过内置的算法,对添加的b2Body刚体模拟物理运动,但是b2Body并不是显示对象,也就是说无法通过addChild添加到舞台上并显示。Box2D中通过b2DebugDraw类,绑定一个Sprite对象,并通过调用它的Graphics的绘图API,绘制出b2Body,让开发者可以调试自己的应用。当然如果要添加自己的MovieClip,可以参考我的教程刚体的上衣——b2BodyDef.userData。
这样解释,你可以明白了吗?至于怎么debugDraw的中文怎么说,随便了,知道自己明白就行。
我是用Flash Develop写代码,Flash cs IDE的编辑器功能太少了。
谢谢,感谢你的耐心及时的回答,再追问一个问题,绘制出b2Body刚体与那个Sprite对象是什么关系,b2Body刚体是Sprite对象的子对象吗,那个Sprite对象在舞台上吗(是作为一个空的对象放到舞台上吗,只是我们看不见?)
今天研究了一天的box2d,对box2d多少理解了一些,多谢你的教程,你的教程发现是网上写的最好的,建议可以出这方面的书,
我想问下,box2d较成熟的应用有没有,有没有通过它做出来的游戏什么的
有几个名称我翻译的,你看怎么样(我觉得哪些类和方法最好有个贴切的中文翻译,毕竟我们的母语是中文,中文好理解,我上次看box2d头都大了,相信很多初学者和我一样的感受,今天硬着头皮看下去,才基本上看懂了):
aabb:轴对齐边界框, 其实就是矩形边界框,表示wold的有效范围
debugDraw:调试用绘制刚体
debugDraw.m_drawScale = 30.0;
求解释 m_drawScale 这个属性的意思
请参考这篇文章
非常好的文章,简单明了,排版很清楚!
从事as开发快一年了,对box2d一直是心里的一道坎,一直都过不去,在网上查了很多的资料,要么全是英文,要么不清不楚,现在已看了两章,感觉比网上任何一个helloworld例子让人更易于理解,楼主对于每一个提问者都如此耐心回答,相信别人和我也一样别人提出的问题其实我也一样不清楚,可再看作者的解释脑海里是如此的清晰明了,感谢作者如此无私奉献,相信有了你的这一套教程,我box2d一定可以学好.
谢谢你的评论,其实我一开始学习box2D时,也是摸不着头脑,官方的教程也很专业,所以自己硬着头皮去研究,然后用傻瓜式的语言重新描述,能给大家带来帮助,我很高兴,也希望你能帮我推广,让更多的网友关注我的教程,谢谢啦!
debugDraw.m_drawFlags = b2DebugDraw.e_shapeBit | b2DebugDraw.e_jointBit;
等号右边,中间的那一条 | 是什么意思啊?
是或的意思!官方API里有解释
This is cool!
Cool!