zoukankan      html  css  js  c++  java
  • box2d 重置 重力

    引用:http://bbs.9ria.com/forum.php?mod=viewthread&tid=150711

    【Box2D系列教程】【导航帖】——拉登大叔出品


    今天我们一起来学习自定义刚体重力(修改重力方向或消除重力)。
    在Box2D中创建的非静态刚体,默认情况下都会受到重力作用,自然下落。这是我们希望的。不过有些特殊情况,重力反而是我们不想要的,比如在太空环境中,所有的物体都是处于失重状态,这时候就不需要重力了。这种情况应该怎么用Box2D实现呢?

    在此要特别感谢Emanuele的Managing multiple gravities with Box2D,我也是从中学习到了接下来要讲的方法。

    实现方法有两种:一、加减法抵消重力;二、重置重力。下面我们来详细一下这两种方法。

    一、加减法抵消重力

    重力也是里的以一种,也有大小和方向。它的方向与y轴一致,所以可以用一个正数表示重力,如:G。那么要消除重力,即受力为0,只要G-G=0就可以了。也就是说,再给刚体施加一个-G的力,负数表示力的方向与y轴相反。

    关于对刚体施加里的方法,请参考让刚体听到的——ApplyForce一文。

    值得注意的是,重力等于刚体的质量乘以重力加速度,所以在施加外力时,不要忘了乘以刚体的质量b2Body.GetMass()。在下面的效果中,点击鼠标创建一个不受重力影响的刚体:

    完整的代码即注释如下:

    1. package
    2. {
    3.     import Box2D.Common.Math.b2Vec2;
    4.     import Box2D.Dynamics.b2Body;
    5.     import Box2D.Dynamics.b2World;
    6.     import flash.display.Sprite;
    7.     import flash.events.Event;
    8.     import flash.events.MouseEvent;
    9.     /**
    10.      * http://www.ladeng6666.com
    11.      * @author ladeng6666
    12.      */
    13.     public class ApplyForce extends Sprite
    14.     {
    15.         private var world:b2World;
    16.         private var debugSprite:Sprite;
    17.         private var body:b2Body;
    18.         public function ApplyForce()
    19.         {
    20.             //创建基本的世界
    21.             world=LDEasyBox2D.createWorld();
    22.             debugSprite=LDEasyBox2D.createDebug(world);
    23.             addChild(debugSprite);
    24.             //创建地面,
    25.             LDEasyBox2D.createWrapWall(world, stage);
    26.             //侦听事件
    27.             addEventListener(Event.ENTER_FRAME, loop);
    28.             stage.addEventListener(MouseEvent.MOUSE_DOWN, onStageMouseDown);
    29.         }
    30.         private function onStageMouseDown(e:MouseEvent):void
    31.         {
    32.             //鼠标按下时,在鼠标位置创建一个刚体
    33.             body = LDEasyBox2D.createCircle(world,mouseX,mouseY,Math.random()*30+10,false);
    34.         }
    35.         private function loop(e:Event):void
    36.         {
    37.             //遍历所有的刚体,并对它们施加一个与重力相等的向上的外力,平衡重力,模拟失重效果
    38.             for (var body:b2Body = world.GetBodyList(); body; body = body.GetNext()) {
    39.                 body.ApplyForce(new b2Vec2(0, -10*body.GetMass()),body.GetWorldCenter());
    40.             }
    41.             //更新Box2D世界
    42.             LDEasyBox2D.updateWorld(world);
    43.         }
    44.     }
    45. }
    复制代码



    效果看起来不错哦。不知道你注意到没有,所有的刚体都是醒着的(Box2D中对于停止运动的刚体,会自动将其设置为睡眠sleep状态,并显示灰色,并且不对其进行物理模拟,以节省CPU开支)。这样CPU的负担并没有降低。

    二、重置重力
    Box2D中的Dynamics包下有一个b2Island类,类中有一个Solve方法,这方法通过gravity形参对刚体进行重力模拟,代码如下:

    1.             b.m_linearVelocity.x += step.dt * (gravity.x + b.m_invMass * b.m_force.x);
    2.             b.m_linearVelocity.y += step.dt * (gravity.y + b.m_invMass * b.m_force.y);
    3.             b.m_angularVelocity += step.dt * b.m_invI * b.m_torque;
    复制代码

    所谓重置重力,就是在这里动手脚了。要怎么做呢?把这个gravity形参改成我们想要的重力,比如可以像下面的代码,设置为0.

    1.             gravity = new b2Vec2(0, 0);
    2.             b.m_linearVelocity.x += step.dt * (gravity.x + b.m_invMass * b.m_force.x);
    3.             b.m_linearVelocity.y += step.dt * (gravity.y + b.m_invMass * b.m_force.y);
    4.             b.m_angularVelocity += step.dt * b.m_invI * b.m_torque;
    复制代码

    或者我们用了一个更便于重用的方法,在b2Body类添加一个b2Vec2类型的公共属性m_customGravity,然后在b2Island.Solve()方法中,判断是否设置了刚体的m_customGravity属性,如果有,则用m_customGravity进行重力模拟计算。然后我们在创建刚体时,只要设置一下m_customGravity属性就可以轻松重置重力了。

    1.             //2012-7-27
    2.             //added by ladeng6666
    3.             //如果刚体有自定义m_customGravity属性,则用其进行重力模拟计算
    4.             if (b.m_customGravity != null) {
    5.                 LDgravity = b.m_customGravity;
    6.             }else {
    7.                 LDgravity = gravity;
    8.             }
    9.             //用更新后的LDgravity属性进行重力模拟计算
    10.             b.m_linearVelocity.x += step.dt * (LDgravity.x + b.m_invMass * b.m_force.x);
    11.             b.m_linearVelocity.y += step.dt * (LDgravity.y + b.m_invMass * b.m_force.y);
    12.             b.m_angularVelocity += step.dt * b.m_invI * b.m_torque;
    复制代码

    在下面的效果中,点击鼠标创建一个不受重力影响的刚体(当然你可以随意设置customer_gravity属性,让重力向上、向左、向右)。按下键盘空格键,创建一个向上"掉"的矩形刚体。点击刚体,可以进行拖动


    完整的代码和注释如下:

    1. package
    2. {
    3.     import Box2D.Common.Math.b2Vec2;
    4.     import Box2D.Dynamics.b2Body;
    5.     import Box2D.Dynamics.b2World;
    6.     import flash.display.Sprite;
    7.     import flash.events.Event;
    8.     import flash.events.KeyboardEvent;
    9.     import flash.events.MouseEvent;
    10.     import flash.ui.Keyboard;
    11.     /**
    12.      * http://www.ladeng6666.com
    13.      * @author ladeng6666
    14.      */
    15.     public class CustomerGravity extends Sprite
    16.     {
    17.         private var world:b2World;
    18.         private var debugSprite:Sprite;
    19.         private var body:b2Body;
    20.         public function CustomerGravity()
    21.         {
    22.             //创建基本的Box2D世界
    23.             world=LDEasyBox2D.createWorld();
    24.             debugSprite=LDEasyBox2D.createDebug(world);
    25.             addChild(debugSprite);
    26.             LDEasyBox2D.stage = stage;
    27.             //创建地面,
    28.             LDEasyBox2D.createWrapWall(world, stage);
    29.             //侦听事件
    30.             addEventListener(Event.ENTER_FRAME, loop);
    31.             stage.addEventListener(MouseEvent.MOUSE_DOWN, mouseEventHandler);
    32.             stage.addEventListener(MouseEvent.MOUSE_UP, mouseEventHandler);
    33.             stage.addEventListener(KeyboardEvent.KEY_DOWN, onStageKeyDown);
    34.         }
    35.         private function onStageKeyDown(e:KeyboardEvent):void
    36.         {
    37.             //当按下键盘空格键时,创建一个重力向上的矩形刚体
    38.             if (e.keyCode == Keyboard.SPACE) {
    39.                 body = LDEasyBox2D.createBox(world,Math.random()*400+50,400,Math.random()*30+10,Math.random()*30+10);
    40.                 body.m_customGravity = new b2Vec2(0, -10);
    41.             }
    42.         }
    43.         private function mouseEventHandler(e:MouseEvent):void
    44.         {
    45.             //鼠标按下时
    46.             if (e.type == MouseEvent.MOUSE_DOWN) {
    47.                 //确认是否点击到刚体
    48.                 var dragBody:b2Body = LDEasyBox2D.getBodyAtMouse(world);
    49.                 if (dragBody != null) {
    50.                     //如果点击到了,则拖动刚体
    51.                     LDEasyBox2D.startDragBody(world, dragBody);
    52.                 }else {
    53.                     //否则创建一个圆形的,不受重力影响的刚体
    54.                     body = LDEasyBox2D.createCircle(world,mouseX,mouseY,Math.random()*30+10,false);
    55.                     body.m_customGravity = new b2Vec2(0, 0);
    56.                 }
    57.             //当鼠标弹起时
    58.             }else if (e.type == MouseEvent.MOUSE_UP) {
    59.                 //停止拖动刚体
    60.                 LDEasyBox2D.stopDragBody(world);
    61.             }
    62.         }
    63.         private function loop(e:Event):void
    64.         {
    65.             //更新Box2D世界
    66.             LDEasyBox2D.updateWorld(world);
    67.         }
    68.     }
    69. }
    复制代码


    代码重点是在45,61行,看到没有customer_gravity按照我们希望的样子自定义了重力,是不是很好用?

    自定义重力可以实现的效果很多,如失重、上升的气球等等,发挥你的想象力,没有什么做不到的。Fighting!

    代码中用到了我写的静态类LDEasyBox2D,可以有效的简化代码,具体请参考这里

    <ignore_js_op> OK 2012-09-06 Box2D自定义重力.rar (426.97 KB, 下载次数: 20) 

  • 相关阅读:
    [CF603C] Lieges of Legendre
    [CF1070A] Find a Number
    [CF431D] Random Task
    2020牛客暑期多校训练营(第二场)C
    2020牛客暑期多校训练营(第二场)F
    2020牛客暑期多校训练营(第二场)D
    2020牛客暑期多校训练营(第一场)H
    [CF1000E] We Need More Bosses
    Java学习2 (ThreadLocal)
    Java复习1
  • 原文地址:https://www.cnblogs.com/sode/p/2729685.html
Copyright © 2011-2022 走看看