您好,欢迎访问一九零五行业门户网

Libgdx专题系列:物理引擎篇 Box2D

声明: 本系列文章使用的libgdx版本均为 0.99 版本 libgdx游戏开发交流群 323876830 box2d的是一个物理引擎库。他是一个用于2d的最流行的物理引擎库中的一个,被用到了许多语言,各种引擎中, 其中就包括咱们使用的这个libgdx。 libgdx中的box2d实现了对于c
声明:
本系列文章使用的libgdx版本均为0.99版本
libgdx游戏开发交流群 323876830
box2d的是一个物理引擎库。他是一个用于2d的最流行的物理引擎库中的一个,被用到了许多语言,各种引擎中,
其中就包括咱们使用的这个libgdx。
libgdx中的box2d实现了对于c++引擎的java包装,所以参考文档也可以直接使用c++版本的,official box2d manual (pdf)
想获得更多的信息可以到box2d的官网,box2d.org 获得信息。
这里我找到一个中文翻译的v2.0.1版本,这里要谢谢译者aman jiang(江超宇)。
文档下载地址
但是v2.0.1的版本比较老了,有一些概念都不一样了,例如2.1世界没有了包围盒,绑定形状到物体有了fixturedef的概念,
这里有一个v2.1.0的翻译版本
http://blog.csdn.net/complex_ok/article/category/871440
特别推荐box2d教程 http://www.iforce2d.net/b2dtut/introduction
对应中文译文 http://ohcoder.com/blog/categories/box2d-tutorials/
创建一个世界
物理世界,那么首先需要创造一个世界,他是物理物体,作用力的基础。但是他不会帮我们绘制物体, 需要我们使用libgdx
绘制的相关api来进行绘制。 也就是说我们获取物体的坐标,旋转信息什么的,然后自己绘制。 但是他在debug模式下,可以
绘制自己的物理模拟信息,形状啦,什么的。
可以向下面一样创建一个世界
world world = new world(new vector2(0, -10), true);
第一个参数是一个2维向量,0说明水平方向的重力为0, 10说明垂直方向的重力为10. 因为他是一个y轴向上的坐标系,所以负号
代表向下。这个和opengl的世界坐标系是一致的。当然你也可以改成你想要的值, 不过要注意比例,在box2d中 1单元=1米。
第二个参数的意思是我们创造的世界要不要让物体休眠,休眠可以减少cpu的使用, 具体休不休眠看你的情景了。
这里的比例最好和绘制的保持一致,也就是我们的opengl绘制。这样精灵,镜头的单位都统一。
debug绘制
如果我们想开启debug绘制, 可以这样
mdebugrender = new box2ddebugrenderer();
mdebugrender.render(mworld, mcam.combined);
这里要注意一下, 当我们发布的时候要注释掉 , 我测试了一个例子, 在开启状态只有十几帧,关闭掉能够达到
五六十帧的,还是很好性能的。
时间步
想要我们的物理模拟动起来, 需要我们告诉他。最好调用它的位置在reader的最后面。
最好给他的帧率是一样的,不要使用绘制的帧率,像这样
world.step(1/60f, 6, 2);
第一个参数是时间步,也就是我们想让世界模拟的时间。
在大部分情况下, 这个时间步都应该是固定的, libgdx推荐在移动手机1/45f或者1/300f.
另外两个参数是velocityiterations,positioniterations 速度的约束求解量 和 位置的约束求解量.
约束求解器用于解决模拟中的所有
约束,一次一个。单个的约束会被完美的求解,然而当我们求解一个约束的时候,我们就会稍微耽误另
一个。要得到良好的解,我们需要迭代所有约束多次。建议的  box2d 迭代次数是 10 次。你可以按自己
的喜好去调整这个数,但要记得它是速度与质量之间的平衡。更少的迭代会增加性能并降低精度,同样
地,更多的迭代会减少性能但提高模拟质量。
绘制
推荐的做法是在step之前绘制我们的图形, 否则将会出现不同步的问题。
如果想要debug绘制, 可以使用
debugrenderer.render(world, camera.combined);
第一个参数是世界,第二个是镜头矩阵
body物体
现在如果我们运行我们的代码,将会什么也看不到,虽然我们的世界步执行着呢, 这是因为我们没有放入
任何物体进去。 所以, 接下来我们会放进去一些物体。
在box2d中, 对象叫做物体, 物体包含许多固定物fixtures,他可以固定物体的位置,方向等, 固定物可以是
任何形状, 可以组合多个不同的固定物来组成物体。
固定物包含形状, 密度, 摩擦力,恢复力。形状就是集合图形了, 密度是每立方米的物体的质量, 就比如保龄球
和氢气球,密度大密度小。摩擦力就是物体接触移动产生的力,在冰上移动和在橡胶上, 摩擦力显而易见了。
恢复力就是有多大的弹性, 石头的弹性就比较小 , 乒乓球的弹性就比较大。 当一个物体的弹性是0的时候, 当接触到
地面就会停止,当为1的时候, 他会反弹到他原来的高度。
物体有三种类型:dynamic动态的,static静态的,kinematic介于他们之间的运动物体。
动态物体
动态物理可以四处移动, 他受力的作用和其他动态物体,静态物体, 运动物体的作用。
他适合那种需要移动然后受到力的作用的物体。
现在我们学习固定物的创建, 来构造物体
// first we create a body definitionbodydef bodydef = new bodydef();// we set our body to dynamic, for something like ground which doesn't move we would set it to staticbodybodydef.type = bodytype.dynamicbody;// set our body's starting position in the worldbodydef.position.set(100, 300);// create our body in the world using our body definitionbody body = world.createbody(bodydef);// create a circle shape and set its radius to 6circleshape circle = new circleshape();circle.setradius(6f);// create a fixture definition to apply our shape tofixturedef fixturedef = new fixturedef();fixturedef.shape = circle;fixturedef.density = 0.5f; fixturedef.friction = 0.4f;fixturedef.restitution = 0.6f; // make it bounce a little bit// create our fixture and attach it to the bodyfixture fixture = body.createfixture(fixturedef);// remember to dispose of any shapes after you're done with them!// bodydef and fixturedef don't need disposing, but shapes do.circle.dispose();
现在我们创建了一个球的物体到我们的世界。运行的时候可以看到他将会下落, 但是感觉还是没多少意思,
没有力的作用, 下面我们来加入静态物体地板。
静态物体
静态物体是一个不能移动, 也不受力的作用的物体。动态物体接触它, 动态物体会有力的作用的。静态物体
让他来做为地板,墙壁等不能动的物体是非常合适的。 静态物体也消耗比较少的计算量。
让我们来创建一个静态物体, 跟我们前面的创建动态物体的代码比较像
// create our body definitionbodydef groundbodydef =new bodydef(); // set its world positiongroundbodydef.position.set(new vector2(0, 10)); // create a body from the defintion and add it to the worldbody groundbody = world.createbody(groundbodydef); // create a polygon shapepolygonshape groundbox = new polygonshape(); // set the polygon shape as a box which is twice the size of our view port and 20 high// (setasbox takes half-width and half-height as arguments)groundbox.setasbox(camera.viewportwidth, 10.0f);// create a fixture from our polygon shape and add it to our ground body groundbody.createfixture(groundbox, 0.0f); // clean up after ourselvesgroundbox.dispose();
我们怎么样不适用fixturedef创造一个夹具呢?如果我们只有形状和密度, createfixture有个重载方法,调用它就可以了。
现在我们看到, 球下落到我们的地面上, 然后反弹, 最终停止在地面上, 我们也可以更改其中的值来看看有什么其他效果。
运动物体
kinematic物体是一个介于在静态和动态物体之间的物体。 像静态物体,他们不受力的作用, 像动态物体,他们可以移动。
应用的场景例如移动的平台等。
我们可以直接的调用kinematic物体的位置,直接更改他的位置, 但是最好的方式是设置一个速度,让box2d自己来更改
他的坐标。
我们可以使用上面创建动态和静态物体的方式一样来创建这个物体, 一旦我们创建好, 我们可以像下面一样来控制他
// move upwards at a rate of 1 meter per secondkinematicbody.setlinearvelocity(0.0f, 1.0f);
好了, 运行程序, 我们发现, 我们的物体在朝着一个固定的方向移动, 当我们的小球遇到咱们这个方块的时候,由于力
的作用,朝右方向移动了,但是它与静态物体地板接触的时候, 并没有受到力的作用, 当然地板也没有力的作用。
冲量与力
冲量和力用来移动物体, 但是不会改变重力和碰撞检测。
力是一个逐渐改变物体速度的过程, 比如火箭的升起,是有一个力的驱动,逐渐改变火箭的速度, 慢慢升起的,越来
越快。
冲量就不同了,可以瞬间改变物体速度,比如吃豆人游戏,角色都是在一个恒定的速度移动,改变也是瞬间的。
首先我们需要一个动态的物体,就使用上面那个吧。
应用力
力是单位是牛顿。 如果力没有作用在质量的中心,那么将会产生一个扭矩, 产生一个带有夹角的速度。
// apply a force of 1 meter per second on the x-axis at pos.x/pos.y of the body slowly moving it rightdynamicbody.applyforce(1.0f, 0.0f, pos.x, pos.y, true);// if we always want to apply force at the center of the body, use the followingdynamicbody.applyforcetocenter(1.0f, 0.0f, true);
应用冲量
冲量就像一个特殊的力,只是冲量可以立即改变物体的速度。 同样的, 如果冲量没有作用在物体的中间, 也将会产生
一个扭矩, 产生一个带有夹角的速度。冲量的单位是 牛顿每秒 或者 kg-m/s.
// immediately set the x-velocity to 1 meter per second causing the body to move right quicklydynamicbody.applylinearimpulse(1.0f, 0, pos.x, pos.y, true);
有一点要注意一下,应用力和冲量会唤醒物体, 有时候这不是我们想要的, 比如, 你想作用一个稳定的力,想让物体在睡眠中执行,
这种情况下, 我们可以这样
// apply impulse but don't wake the bodydynamicbody.applylinearimpulse(0.8f, 0, pos.x, pos.y, false);
joints关节
占位
fixture shapes形状
占位
sprites and bodies 精灵与物体
最简单的方式管理精灵语物体的是使用box2d的用户数据,我们可以使用用户数据改变游戏对象的位置坐标, 旋转等信息。
设置用户信息也比较简单,可以这样
body.setuserdata(object);
这个用户数据可以是任何java对象, 一个比较好的方式是建立一个游戏对象然后放入用户数据,这样以后可以使用。
fixtures夹具也可以设置用户数据,和上面一样。
想更新我们的角色或精灵的信息, 可以遍历所有的世界物体,取出对应的用户数据,然后更新信息, 示例
iterator bi = world.getbodies(); while (bi.hasnext()){ body b = bi.next(); // get the bodies user data - in this example, our user // data is an instance of the entity class entity e = (entity) b.getuserdata(); if (e != null) { // update the entities/sprites position and angle e.setposition(b.getposition().x, b.getposition().y); // we need to convert our angle from radians to degrees e.setrotation(mathutils.radianstodegrees * b.getangle()); }}
绘制部分还是和以前一样的。 没有什么改动。
sensors传感器
传感器是当物体间碰撞,而又不产生自动响应。 比如, 我们想知道两个物体重叠的事件。
这里需要设置'issensor'为true。像这样
//at the definition of the fixturefixturedef.issensor = true;
想监听它,需要实现contactlistener接口,在对应方法中实现自己的逻辑。
传感器接口
传感器接口监听fixture夹具的碰撞,方法包含一个传感对象, 传感对象包含了两个物体的有关信息, 当物体重叠的时候
调用begincontact ,当物体分开的时候调用endcontact
public class listenerclass implements contactlistener { @override public void endcontact(contact contact) { } @override public void begincontact(contact contact) { } };
有时候, 我们需要得到游戏对象的信息, 怎么办呢?其实这个在我们需要在设置用户数据的时候, 把我们的游戏对象信息设置
到body或者fixture中, 然后取出来, 做逻辑,比如,减血或其他。
好了, box2d的简单的了解,就到这了。 想深入学习,可以到他的官网查看。
项目下载地址
截屏
http://blog.csdn.net/wu928320442/article/details/17285405
其它类似信息

推荐信息