Oh!Coder

Coding Life

Box2D C++ 教程-跳跃

| Comments

声明:本教程翻译自:Box 2D C++ turorials - Jumping,仅供学习参考。

  • 跳跃(Jumping)

水平滚轴游戏中的角色可以进行跳跃,是吧?现在就让我们看看几种不同实现跳跃的方法。我们已经在之前力和冲量(force and impulses)的话题中进行过相关问题的讨论,但是现在就让我们考虑一下如何把这些方法整合到游戏中。我们可以从匀速运动(moving at constant speed)这个话题开始,在一定范围内左/右控制移动一个动态物体。

pic

  • 直接设置速度

当玩家跳跃的时候他们的速度就会改变,让我们以此为起点。首先在Keyboard()方法中添加一个case分支,来获得玩家的跳跃输入:

1
2
3
4
5
6
7
case 'j': //jump
{
    b2Vec2 vel = body->GetLinearVelocity();
    vel.y = 10;//upwards - don't change x velocity
    body->SetLinearVelocity( vel );
}
break;

现在按下键盘j就会直接改变物体的速度,当然我们知道,这种方式并不是真实世界里的物理方法。对于横屏游戏中的跳跃使用这种方法可能不太合适,这里有几点需要注意的地方。首先这样做物体自身的动量没有考虑其中,当玩家快速掉落的时候可以用相等的力跳起。玩家可以在半空中进行跳跃-也许这种现象正是你想要的,美其名曰‘连跳’特性。接下来我们会解决这个半空跳跃的问题,稍后我们会讨论玩家跳跃之后是否着地。

  • 使用力

现实生活中,当你真正跳跃的时候,你会在自己身体上施加一个向上的力,那么让我们看看对物体连续几帧施加强力能否达到此效果。在Keyboard()方法中我们将简单做一个跳跃开始的标记,在Step()方法中完成力的施加。使用一个类的成员变量来记录每次的每次应该施加多少帧的力:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//class member variable
int remainingJumpSteps;

//in constructor
remainingJumpSteps = 0;

//keyboard function
case 'k': //jump
    remainingJumpSteps = 6;// 1/10th of a second at 60Hz
    break;

//in Step() function
if ( remainingJumpSteps > 0 ) {
    body->ApplyForce( b2Vec2(0,500), body->GetWorldCenter() );
    remainingJumpSteps--;
}

现在尝试着按下k键。和之前类似,但是这次当物体下落的时候,因为下降的动量考虑在内,所以跳跃效果会减小很多。这里使用的力只是一个看起来差不多的数值。如果你想指定物体产生起飞(take-off)的速度,需要使用之前推算力矩的公式,根据你想让物体左/右移动的速度推算出相应的力矩(f=mv/t),在每一帧中对物体施加此作用力:

1
2
3
4
5
6
7
8
if ( remainingJumpSteps > 0 ) {
    //to change velocity by 10 in one time step
    float force = body->GetMass() * 10 / (1/60.0); //f = mv/t
    //spread this over 6 time steps
    force /= 6.0;
    body->ApplyForce( b2Vec2(0,force), body->GetWorldCenter());
    remainingJumpSteps--;
}
  • 使用冲量

这种方法可能会是你经常用到的,本质上是使用上面相同的力,只在一个时间步长中完全实现相应的效果。正如之前话题中提到的那样我们可以忽略时间部分:

1
2
3
4
5
6
7
case 'l':
{
    //to change velocity by 10
    float impulse = body->GetMass() * 10;
    body->ApplyLinearImpulse(b2Vec2(0, impulse),body->GetWorldCenter());
}
break;

这种方法比施加作用力更接近直接改变速度的效果,因为每一帧都会有力对物体的作用,重力起到了下降的作用。其实,如果你离近点仔细观看,会发现直接使用作用力来实现跳跃并不能和另外两种方法那样跳的一样高。然而,如果你想实现一种缓慢跳起的效果,来取代直接跳起,那么作用力方法会更有用。

  • 其它方法

在真实世界里,每一个动作都会产生一个大小相等,方向相反的作用。如果你使用腿推动身体跳向空中,无论你站在哪里,都会产生一个相等的向下推力。上面的所提到的方法都没有把这一点考虑在内,然而大部分游戏里也不需要考虑这些。但是如果你需要模拟这种情况,这里有两种可以实现的方法,这两种方法需要我们再多学习一点才能实现,所以现在我只是顺带提一下。

当确定玩家站在什么物体上之后,如果此物体是动态物体,那么你应该对此物体施加相同的力/冲量。这就像你站在秋千桥(swing bridge)上进行跳跃一样,比如说,当玩家跳起的时候,桥会瞬间得到一个取代玩家重力的向下推力。为了达到这种效果,我们需要知道如何告诉玩家接触到了什么。

使用棱镜(滑动)连接器(prismatic(sliding)joint)把两个物体连接起来能更快的模拟物体跳跃的效果。使用这种方法,玩家需要拥有一个主物体,比如我们正在使用的这个,另一个连接着的是可以上下滑动的小物体。连接器马达(joint motor)可以向下推小物体,就像是你用腿进行起跳一样。这么做有一个好的优点是我们不用很麻烦的去检查,物体到底站在一个什么样的地方,因为如果玩家所站立的下方不能保证‘腿’能将身体推向上方,那么玩家什么也不发生。此外,如果玩家站立的地方比较‘软’,就像秋千桥一样,那么玩家的跳起效果将会减小,就像真实世界一样。当然除了能够完成更多效果以外,还是会有它自身需要考虑的问题的。我希望这个话题可以放到连接器以及马达连接器讲解之后再进行深入探讨。

  • 让物体从旋转中停止

你可能已经注意到那个让被我们看做玩家的物体不停的在一定区域内自由的做旋转。一个简单而又奏效的方法是把物体设置成固定旋转体:

1
body->SetFixedRotation(true);

Comments