Box2D浮力效果
前些天有人问到Box2D如何实现浮力效果。今天我们就来学习一下。
Box2D浮力效果实现起来并不难。无非就是当刚体接触到水面时,对它施加一个向上的浮力。不过这个浮力受到刚体体积的影响,体积越大,收到的浮力也越大。同时还会因为受力点不在中心位置,而引起角度旋转。
额…。综合这些因素,用b2Body.ApplyForce实现起来似乎有些困难,所以我们要引入一个新的类:b2BuoyancyController。
b2BuoyancyController是b2Controller的一个子类,b2Controller类用来集成一些常用的功能,为用户免去复杂的算法。比如今天我们要学习的浮力效果,就可以用它的子类b2BuoyancyController来实现。
b2BuoyancyController和b2Body刚体不同。它是不可见的Box2D对象,也就是说,b2DebugDraw中不会绘制b2BuoyancyController的实例。但是当它与刚体发生碰撞时,Box2D会自动计算所浮力,并施加到刚体上,进而模拟漂浮效果。
b2BuoyancyController的构造函数非常简单,没有任何参数。
var bc:b2BuoyancyController = new b2BuoyancyController();
它常用的公共属性有:
- normal:指定水面法向量的方向,也就垂直水面的方向,通常保持默认的(0,-1)不变。
- offset:指定水面的偏移量。注意它的方向与AS3中的y轴方向相反,也就是说如果我们想设置水面位置的y为200,那么offset属性应该是-200/30。
- density:设置水的密度。确切的讲,是设置液体介质的密度。我们知道,只有漂浮物的密度小于液体介质的密度时,才可以漂浮在该介质上。(当然,要讲到刚结构的轮船可以漂浮在水上,就要讲到排水量要大于轮船的重量上了,话题就扯远啦,就此打住。)
- linearDrag:设置漂浮物在水中移动的阻尼值。或者我们可以把它想象成水的粘稠度。这个属性值越大,漂浮物移动的速度越慢。
- angularDrag:设置漂浮物在水中旋转的阻尼值。
- velocity:设置水流动的速度。
b2BuoyancyController用起来也很简单,首先创建一个b2BuoyancyController实例。
//实例化b2BuoyancyController对象 fuliController = new b2BuoyancyController();
然后设置它们的一些属性,比如水面的位置、方向、密度等等。
//设置水面的法向量 fuliController.normal.Set(0, -1); //设置水面的位置 fuliController.offset = -200 / m_physScale; //设置水的密度,因为我们创建的刚体密度是3,所以水的密度要大于3 fuliController.density = 5.0; //设置刚体在水中的移动阻尼 fuliController.linearDrag = 10; //设置刚体在水中的旋转阻尼 fuliController.angularDrag = 6;
然后,将fuliController添加到b2world世界中
//将水面、浮力控制器添加到世界中 world.AddController(fuliController);
创建刚体后,如果希望它与fuliController交互,实现漂浮效果,则用b2BanyancyController.AddBody方法,将漂浮物体添加到fuliController中
//将刚体添加到水面上 fuliController.AddBody(body);
是不是很简单?在下面的效果中,用鼠标拖动刚体,看看浮力的效果是不是很满意?!
完整的代码和注释如下:
package { import Box2D.Common.Math.b2Vec2; import Box2D.Dynamics.b2Body; import Box2D.Dynamics.b2World; import Box2D.Dynamics.Controllers.b2BuoyancyController; import Box2D.Dynamics.Controllers.b2Controller; import flash.events.Event; import flash.events.MouseEvent; import flash.display.Sprite; /** * ... * @author ladeng6666 */ public class FuliTest extends Sprite { //声明世界变量 private var world:b2World; //定义浮力控制器,也就是水面 private var fuliController:b2BuoyancyController; //因为b2BuoyancyController是不可见的,所以我们专门为它定一个图层 private var controllerLayer:Sprite; //像素和米的转换关系 private const m_physScale:Number = 30; public function FuliTest() { //创建世界 initWorld(); //创建水面,浮力控制器 createController(); //创建刚体 for (var i:int = 0; i < 8; i++) { createBodies(); } } private function createBodies():void { //创建刚体 var body:b2Body = LDEasyBox2D.createBox(world, Math.random()*400+50, Math.random()*50+30, Math.random()*20+30, Math.random()*20+30); //将刚体添加到水面上 fuliController.AddBody(body); } //创建水面、即浮力控制器 private function createController():void { //实例化b2BuoyancyController对象 fuliController = new b2BuoyancyController(); //设置b2BuoyancyController对象的一些基本属性 //设置水面的法向量 fuliController.normal.Set(0, -1); //设置水面的位置 fuliController.offset = -200 / m_physScale; //设置水的密度,因为我们创建的刚体密度是3,所以水的密度要大于3 fuliController.density = 5.0; //设置刚体在水中的移动阻尼 fuliController.linearDrag = 10; //设置刚体在水中的旋转阻尼 fuliController.angularDrag = 6; //将水面、浮力控制器添加到世界中 world.AddController(fuliController); //因为b2BuoyancyController是不可见的,所以要为水面添加一个图层,专门绘制水面 controllerLayer = new Sprite(); addChild(controllerLayer); controllerLayer.graphics.lineStyle(1,0x0000ff,1); controllerLayer.graphics.moveTo(0,200); controllerLayer.graphics.lineTo(550,200); controllerLayer.graphics.lineStyle(); controllerLayer.graphics.beginFill(0x0000ff,0.2); controllerLayer.graphics.drawRect(0, 200, 550, 300); controllerLayer.graphics.endFill(); } private function initWorld():void { //创建b2World世界 world = LDEasyBox2D.createWorld(); addChild(LDEasyBox2D.createDebug(world)); LDEasyBox2D.createWrapWall(world, this); LDEasyBox2D.stage = this; addEventListener(Event.ENTER_FRAME, loop); stage.addEventListener(MouseEvent.MOUSE_DOWN, mouseEventHandler); stage.addEventListener(MouseEvent.MOUSE_UP, mouseEventHandler); } private function mouseEventHandler(e:MouseEvent):void { //鼠标按下后拖动刚体,弹起后释放刚体 if (e.type == MouseEvent.MOUSE_DOWN) { var body:b2Body = LDEasyBox2D.getBodyAtMouse(world); if (body != null) { LDEasyBox2D.startDragBody(world, body); } }else if (e.type == MouseEvent.MOUSE_UP) { LDEasyBox2D.stopDragBody(world); } } private function loop(e:Event):void { LDEasyBox2D.updateWorld(world); } } }
联系作者
水面能弄出波浪效果吗?
如果弄出波浪,水面的法线就不固定了,该什么处理呢?
楼主的教程前面都看了,在做游戏的时候遇到问题直接到这里查。写得不错,帮助很大,希望楼主继续写教程,好人一生幸福平安。谢了、请问这里能不能帮忙解答问题的呢?
我会尽量回复大家留下来的问题。
另外最近有点忙,没有及时更新教程,sorry。
I have seen a lot of blogs in blogspot. What purpose do they serve? Is it possible to make money through blogs. If yes how?.
这个比较复杂,涉及到的算法b2BuoyancyController的算法有很大差别,Box2D的作业也在自己的网站中说到过,请参考这里http://personal.boristhebrave.com/project/b2buoyancycontroller
请问制作类似绳索的要怎样弄的呢??类似切绳子的游戏
请问,无阻尼的小球在U型坡道来回滚动,这个无阻尼状态怎么实现?
关于U型轨道,请参考我的文章创建圆形Box2D边界,无阻尼的画,可以设置friction都是0,再不行就applyForce,你试试看先!
Thanks like your Box2D浮力效果 Ladeng6666-专业的Flash/AS3爱好者
那风的效果跟浮力效果有什么不同呢
风的效果也浮力效果类似,不过风的方向不一定是向上的,它更像是一个在有限区域内浮力效果。
不过,我还是建议通过添加作用力实现风的效果!
拉登你以前博客上那个image effect不再更新了么~
拉登,你以前博客上的image effect不再更新了么~
是的,不更新了,已经译完给出版社了,期待买实体书看吧!哈哈!
我想问一个问题,b2BuoyancyController的影响范围是怎么决定的?也就是这个水面的宽度和高度是如何决定的?
这样说来,物体放入水中水面应该上升才对是不是也应该考虑进去呢?还有可不可以用许许多多很小的小球来模拟水呢?
可以的,但是这样效率比较差,你可以参考这篇文章http://bbs.9ria.com/thread-127678-1-1.html