1 前言
最近学习libgdx的时候暂时先没看box2d那部分,昨天想做个物理效果看了一下那部分的封装,发现没点概念太难看懂了,还是乖乖的把box2d先系统的学习一遍。这个资料网上很多,最好的自然是官方的用户手册,还有热心网友把翻译成中文的了。还是老习惯,学完以后留点东西以备忘。
2 基础知识
以下内容对理解物理引擎非常重要,摘自用户手册,这部分主要是给自己做备忘,强烈建议读者把《box2d中文手册》研读一遍。
2.1 必要知识
质量(mass),力(force),扭矩(torque)和冲量(impulses),这个不懂看看物理知识。
2.2 核心概念
形状(shape)
2D几何对象, 比如圆形(circle)或多边形(polygon)。
刚体(rigid body)
十分坚硬的物质, 坚硬得像钻石,它上面任意两点之间的距离都保持不变。在后面的讨论中,我们用物体(body)来代替刚体。(这就使得物体本身不会产生形变,那软软弹弹的效果应该都是动画)
夹具(fixture)
fixture将形状绑定到物体之上, 并有一定的材质属性, 比如密度(density), 摩擦(friction)和恢复(restitution)。
(译注:一个物体和另一物体碰撞, 碰撞后速度和碰撞前速度的比值会保持不变,这比值就叫恢复系数。)
约束(constraint)
约束是个物理连接, 用于消除物体的自由度。在2D中, 物体有3个自由度(水平,垂直,旋转)。如果我们把一个物体钉在墙上(像钟摆那样), 那就把它约束到了墙上。这个时候,此物体就只能绕着钉子旋转, 所以这个约束消除了它2个自由度。
(译注:简单的说, 需要用几个参数来确定物体的空间状态, 这个物体就有几个自由度。在二维中,完全没有约束的条件下, 我们要确定物体的状态, 要有x坐标, y坐标, 旋转角这三个参数, 所以自由度为3。如果物体被钉在墙上, 只要有旋转角,就可以完全确定物体的状态,有了钉子这个约束,物体自由度就变成了1。)
接触约束(contact constraint)
一种特殊的约束, 设计的目的是为了防止刚体被穿透, 也用于模拟摩擦和恢复。接触约束不用你来创建, 它们会自动被Box2D生成。
关节(joint)
关节就是种约束, 用于将两个或多个body固定到一起。Box2D支持不同的关节类型:转动(revolute),棱柱(prismatic),距离(distance)等。一些关节可以有限制(limits)和马达(motors)。
关节限制(joint limit)
关节限制限定了一个关节的运动范围。例如人类的胳膊肘只能在某一角度范围内运动。
关节马达(joint motor)
根据关节的自由度, 关节马达可以驱动关节所连接的物体。例如, 你可以使用一个马达来驱动一个肘的旋转。
世界(world)
一个物理世界就是各种, 刚体(bodies), 夹具(fixtures), 约束(constraints)相互作用的集合。 Box2D支持创建多个世界, 但这通常没有必要。
box2d的内存是自己管理的,他建立了一个内存池,以减少对内存的频繁的申请和释放。所以所有对象都要box2d帮你创建,也就是libgdx中的world。
2.3 模拟物理世界的相关算法
积分器(integrator)的数值算法:在离散的时间点上模拟连续的物理方程。它与传统的游戏动画循环一同运行。我们需要为Box2D选取一个时间步。通常来说用于游戏的物理引擎需要至少 60Hz 的速度,也就是 1/60 的时间步。你可以使用更大的时间步,但是你必须更加小心地为你的世界调整定义。我们也不喜欢时间步变化得太大,所以不要把时间步关联到帧频(除非你真的必须这样做)。直截了当地,这个就是时间步:
约束求解器(constraint solver):用于解决模拟中的所有约束,一次一个。单个的约束会被完美的求解,然而当我们求解一个约束的时候,我们就会稍微耽误另一个。要得到良好的解,我们需要多次迭代所有约束。所以就有必要控制迭代计算的次数以防止无限循环,推荐迭代次数为10能较好的模拟效果。
2.4 fixture中一些有意思的概念
密度(Density)
fixture的密度用来计算父物体的质量属性。密度值可以为零或者是整数。你所有的fixture都应该使用相似的密度,这样做可以改善物体的稳定性。
当你添加一个fixture时,物体的质量会自动调整。
摩擦(Friction)
摩擦可以使对象逼真地沿其它对象滑动。Box2D支持静摩擦和动摩擦,两者都使用相同的参数。摩擦在Box2D中会被精确地模拟,摩擦力的强度与正交力(称之为库仑摩擦)成正比。摩擦参数经常会设置在0到1之间, 也能够是其它的非负数,0意味着没有摩擦, 1会产生强摩擦。当计算两个形状之间的摩擦时,Box2D必须联合两个形状的摩擦参数。
恢复(Restitution)
恢复可以使对象弹起。恢复的值通常设置在0到1之间。想象一个小球掉落到桌子上,值为0表示着小球不会弹起, 这称为非弹性碰撞。值为1表示小球的速度跟原来一样,只是方向相反, 这称为完全弹性碰撞。
传感器(Sensors)
有时候游戏逻辑需要判断两个fixture是否相交,但却不应该有碰撞反应。这可以通过传感器(sensor)来完成。传感器也是个fixture,但只会侦测碰撞而不产生其它反应。
2.5 body中一些有意思的概念
阻尼(Damping)
阻尼用于减小物体在世界中的速度。阻尼跟摩擦有所不同,摩擦仅在物体有接触的时候才会发生。阻尼并不能取代摩擦,往往这两个效果需要同时使用。
休眠参数(Sleep Parameters)
休眠是什么意思? 模拟物体的成本是高昂的,所以如果物体更少,那模拟的效果就能更好。当物体停止了运动时, 我们会希望停止模拟它
固定旋转(Fixed Rotation)
你可能想一个刚体,比如某个角色,具有固定的旋转角。这样物体即使在负载下,也不会旋转。
×××(Bullets)
游戏模拟通常以一定帧率(frame rate)产生一系列的图片。这就是所谓的离散模拟。在离散模拟中,在一个时间步内刚体可能移动较大距离。默认情况下,Box2D会通过连续碰撞检测(CCD)来防止动态物体穿越静态物体。一般情况下,dynamic物体之间不会应用CCD,这是为了保持性能。
3 libgdx中的box2d
3.1 libgdx的优势
有个不得不说的优点,box2d用户手册里面有相当篇幅在说如何管理内存和引用,这个对于java程序而言真的是再不用多考虑了。
另外,jbox2d版本在性能方面有些问题,但牛逼的是libgdx是通过jni调用的box2d的c++版本。
3.2 如何将actor和body联系起来
这个问题真的有点让我困扰,我们期望的效果自然是actor能带上物理特性,但遗憾的是不能直接这么指定。这就造成了一个是在物理世界移动的物理,一个是动画世界的图片,两者却没有了直接关系。所以这就需要将这两个东西联系在一起,然后同步两者的为止。
目前觉得比较好的方式就是在上层再做一次封装,将actor和相应的body绑定在一起,每帧都先让body去计算位移,然后再调整actor的位置。
4 总结
物理引擎真的很强大,能通过对物理定义就变成一个可以按物理逻辑运行的效果,但在这之前对于box2d的概念必须有所了解。在libgdx中调用box2d还是比较方便的,就是可惜还要自己去绑定。Loving libgdx ~~
参考资料:
1. box2d v2.0.1中文手册:http://wenku.baidu.com/view/153e4421af45b307e8719753.html
2. box2d与精灵(sprite)的同步:http://blog.u250.info/?p=121002
3. 使用box2d的注意事项:http://kongweile.iteye.com/blog/978718
4. box2d v2.1.0中文手册(有译注,也新一些,推荐):http://blog.csdn.net/complex_ok/article/details/6706982