Box2D C++教程8-力和冲量

Box2D C++教程8-力和冲量

本文出自https://shuwoom.com博客,欢迎访问!

转载自:http://www.ohcoder.com/post/2012-06-15/40027604020

力和冲量(Forces and impulses)

让物体移动,需要对其施加力或者冲量。对物体施加力的作用可以通过时间的不断积累来改变物体的运动,而冲量则是瞬间作用于物体。举个例子,假如现在你的车坏了,你想推动它,你可以用另外一辆车,对这两坏了的车不断的施加力的作用,通过时间不断的积累慢慢的让车移动。也可以用冲量,全速瞬间推动这辆坏车。两种作用力都有你的用武之地。

你也可以通过简单设置物体的位置来瞬间弯曲(warp)’物体。在游戏中你可能想有一个瞬移的特性,但是你要知道这并不是真正的物理世界!Box2D的全部重点是模拟看起来更真实的物理世界,本着这一点我可能会建议你尽量使用力和冲量来移动物体。有时候通过作用力或冲量这种办法来达到你所想象的效果似乎很困难,但是在真实的世界里所有事情的发生都是通过力和冲量的,除非你就是想创建一个不是真实世界里的特性(瞬移,等等)。这么做或许可以给你带来更少的问题。

角运动也可以通过力和冲量来控制,效果就像上面提到的缓慢/瞬间的线性版本一样。角力矩也称为扭矩(torque)。可以想象成转动强度,就像你拧瓶盖儿一样-瓶盖哪里都不会去,但是你可以持续对瓶盖施加作用力(扭矩,torque)

本次话题,我们将创建三个物体,使用上面提到的两种力来分别作用于它们平移或拧(twist)它们。让我们设置一个和定制器(fixtures)一节类似的场景,但不同的是所有物体的形状都一样。

//class member variable to keep track of three bodies

b2Body* bodies[3];

        

FooTest() {

  //body definition

  b2BodyDef myBodyDef;

  myBodyDef.type = b2_dynamicBody;

        

  //shape definition

  b2PolygonShape polygonShape;

  polygonShape.SetAsBox(1, 1); //a 2x2 rectangle

        

  //fixture definition

  b2FixtureDef myFixtureDef;

  myFixtureDef.shape = &polygonShape;

  myFixtureDef.density = 1;

        

  //create identical bodies in different positions

  for (int i = 0; i < 3; i++) {

    myBodyDef.position.Set(-10+i*10, 20);

    bodies[i] = m_world->CreateBody(&myBodyDef);

    bodies[i]->CreateFixture(&myFixtureDef);

  }

          

  //a static floor to drop things on

  myBodyDef.type = b2_staticBody;

  myBodyDef.position.Set(0, 0);

  polygonShape.SetAsEdge( b2Vec2(-15,0), b2Vec2(15,0) );

  m_world->CreateBody(&myBodyDef)->CreateFixture(&myFixtureDef);

}

线性运动(Linear movement)

我们需要一些不使用鼠标就能影响物体运动的方法。现在是考验testbed框架中键盘输入特性的时候了。覆盖Test类中Keyboard方法,来为每个物体施加不同的作用力。

voidKeyboard(unsigned charkey)

  {

    switch(key)

    {

      case'q':

        //apply gradual force upwards

        bodies[0]->ApplyForce( b2Vec2(0,50), bodies[0]->GetWorldCenter() );

        break;

      case'w':

        //apply immediate force upwards

        bodies[1]->ApplyLinearImpulse( b2Vec2(0,50), bodies[1]->GetWorldCenter() );

        break;

      case'e':

        //teleport or 'warp' to new location

        bodies[2]->SetTransform( b2Vec2(10,20), 0 );

        break;

      default:

        //run default behaviour

        Test::Keyboard(key);

    }

  }

其中SetTransform方法已经在物体(bodies)话题中讨论过了。ApplyForceApplyLinearImpulse方法传入了两个参数,第一个参数是力矩,本例中是线性增加。第二个参数是作用于物体的具体位置-之后会再次提到。

运行测试然后按下q/w/e按键。受到冲量作用的物体就像突然碰到什么东西一样做出反应。这个运动的物体被瞬间移动到一个新位置,但是注意它仍然停留了原来的线性和角速度。我们对物体施加作用力会怎么样呢?Keyboard方法只有当我们按下按键的时候才会被调用,不是每个时间步长都会调用。既然作用力需要不停的进行施加,那么我们怎样做才能让力的作用不断的施加到物体上呢?我们需要一个类的成员变量来记录保持当前作用力的状态,使用q键来完成此任务。对类做出如下修改:

//class member variable

boolforceOn;

     

//inside constructor

forceOn = false;

     

//modified case for q key in Keyboard() function

  case'q':

    forceOn = !forceOn;//toggle bool value

    break;

     

//inside Step() function

    if(forceOn)

      bodies[0]->ApplyForce( b2Vec2(0,50), bodies[0]->GetWorldCenter() );

现在q键可以打开或关闭作用力的状态,并且能够看到对物体持续施加力的效果。

...我们使用了相同大小(50)的力和冲量,但是为什么力的效果看起来比冲量不明显呢?嗯,那是因为重力也是作用力。试着关闭重力效果或许能让这个问题的答案更清晰一些。原因是因为力每个时间步长(timestep)让物体上移一点,随后重力的作用下物体又下降一点。就这样不断的上下上下的做斗争。那么对于冲量来说,在重力对物体进行干涉之前完成了所有的工作。关闭重力作用,试着让力作用1秒钟,紧接着停止对物体施加作用力。你会注意到,一秒钟力的作用效果和冲量的作用效果有相同的速度。

现在让我们来看看之前忽略的在施加作用力/冲量方法中所用的第二参数是什么意思?到目前为止我们使用物体中的GetWorldCenter()方法来获取物体的质心,并以此为作用点施加力。正如我们所看到的,当作用力作用于质心的时候并不会引起物体的旋转。想象一下把一张CD放到一张带有摩擦不平的桌子上,例如air-hockey talbe(译者注:美国的一种桌球)。如果你把手指放到CD中间的洞中,然后沿着桌面弹开的话,CD移动的同时并不会发生旋转。但是如果你在CD的其它部位做这种操作,CD会边移动边发生旋转,并且如果你的手指离中心点越远,那么CD在移动的同时旋转的也越厉害。

让我们改变一下之前施加力/冲量的作用点。改变一下ApplyForceApplyLinearImpulse调用的时候使用GetWorldCenter()所获得的质心的位置,这次我们更改为物体的右上角作为力的作用点:

//before

GetWorldCenter()

  

//after

GetWorldPoint( b2Vec2(1,1) )

这次,你应该会看到当盒子们运动的时候,会发生旋转。GetWorldPoint()方法用来将物体自身的坐标(物体坐标系,body coordinates)转换到世界坐标系中,所以即便盒子发生旋转之后我们依然可以把力作用于盒子的右上角。注意当上图的出现在场景中的时候,我们可以表述成拾取盒子角,对于作用于盒子的定制器(fixtures),作用力没有任何作用-力和作用力被应用到物体上,而不是它们的定制器上。力可以作用于任何之前的点上,即便是没有定制器(fixtures)的空点上。

角运动(Angular movement)

角运动被角力矩(扭矩,torque)和角动量所控制。它们的行为和线性运动同理,力是缓慢作用的而角动量是瞬间作用的。让我们在Keyboard()方法中添加一对它们的方法吧(虽然有第三种让物体立刻转动的方法,但我们打算还是像上面一样使用SetTransform()方法,所以这里我们跳过了这些设置)。

case 'a':

    //apply gradual torque counter clockwise

    bodies[0]->ApplyTorque( 20 );

    break;

case 's':

    //apply immediate spin counter clockwise

    bodies[1]->ApplyAngularImpulse( 20 );

    break;

现在,让我们按下a/s按键看看发生了什么。你将会再次看到扭矩的作用效果,下面你需要添加一个类的全局成员变量对扭矩的效果进行开/关效果的切换,这样就可以持续的施加作用效果。

//class member variable

booltorqueOn;

                                               

//inside constructor

torqueOn = false;

                                               

//modified case for a key in Keyboard() function

  case'a':

    torqueOn = !torqueOn;//toggle bool value

    break;

                                               

//inside Step() function

    if(torqueOn)

      bodies[0]->ApplyTorque( 20 );

打开重力效果,你会发现即便我们只是试图扭曲(twist)’这些盒子,但是它们还是会有一点点移动,这仅仅是因为它们会和地面碰撞,并且看起来像是一个矩形的轮子。为了能够看到扭矩和角动量到底都做了些什么,把重力效果关闭。在零重力场景中,我们可以看到转动力矩/角动量为什么只需要一个参数-既然不会引起线性运动,那么唯一我们需要指定的就是转动的方向。由于物体的转动总是绕着物体质心展开,所以不会像上面线性力矩那样产生任何偏离作用点的运动。

想线性力矩一样,传入相同的参数,ApplyTorque执行一秒钟以后会和ApplyAngularImpulse立即执行所产生的角速度相同。

 

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Box2D是一个用于物理模拟的开源库,可以用于模拟刚体的运动和碰撞等物理效果。下面是将Box2D库文件添加到DevC++项目中的步骤: 1. 下载Box2D库文件:你可以从Box2D的官方网站(https://box2d.org/)下载最新版本的库文件。选择适合你操作系统的版本,并下载压缩包。 2. 解压库文件:将下载的压缩包解压到一个你喜欢的位置,得到一个包含Box2D库文件的文件夹。 3. 打开DevC++:启动DevC++集成开发环境。 4. 创建一个新项目:选择“文件”菜单中的“新建”选项,然后选择“项目”。 5. 选择项目类型:在弹出的对话框中,选择“空项目”。 6. 添加Box2D库文件:右键点击项目名称,选择“属性”选项。在属性对话框中,选择“参数”选项卡。在“链接器”选项卡中,点击“添加库或对象文件”按钮。浏览到你解压的Box2D库文件夹中,选择其中的lib文件夹,然后选择适合你编译器的版本(通常是Debug或Release)。在该文件夹中,选择libbox2d.a(对于Linux)或box2d.lib(对于Windows)文件。点击“打开”按钮。 7. 添加Box2D头文件路径:在属性对话框中,选择“目录”选项卡。点击“添加”按钮,浏览到你解压的Box2D库文件夹中,选择其中的include文件夹。点击“打开”按钮。 8. 编写代码:现在你可以在DevC++中编写使用Box2D库的代码了。记得在代码中包含Box2D的头文件,并使用Box2D的命名空间。 9. 编译和运行:保存你的代码,并点击DevC++工具栏上的“编译并运行”按钮,或者按下F9键进行编译和运行。 希望以上步骤对你有所帮助!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值