Libgdx、物理、加速和 FPS

2022-01-12 00:00:00 game-physics physics java libgdx frame-rate

我正在 Libgdx 框架中制作平台游戏.我想实现为我的角色跳跃的能力.我使用简单的公式:

I am making a platform game in the Libgdx framework. I want to implement the ability to jump for my character. I use the simply formula:

speed += acceleration * delta_time
r += speed * delta_time

它运行良好,但仅适用于每秒恒定帧数.FPS 越低,我的角色跳跃越低.我不知道这种行为的原因是什么,跳跃的高度应该是一样的:/我的代码有一个片段:

It works well, but only for constant frames per second. The lower FPS is, the lower my character jumps. I have no idea what is the cause of this behavior, the height of jumps should be the same :/ There is a fragment of my code:

delta_time=Gdx.graphics.getDeltaTime();
if(input.getUpArrow()){
     if(is_in_air==false){
        is_in_air=true;
        speed_y=speed_y_0;
     }
  }

  if(is_in_air==true){
     speed_y-=acceleration*delta_time;
  }
  else{
     speed_y=0;
  }
  
  x+=speed_x*delta_time;
  y+=speed_y*delta_time;

这是一个插图(黑点是字符位置):http://i.imgur.com/tfSTM.jpg

And here is an illustration (black dots are character positions): http://i.imgur.com/tfSTM.jpg

推荐答案

鉴于您使用的积分器非常简单且高度不准确,这是完全正常的行为.做数学并证明这一点很容易.

This is perfectly normal behaviour given the very simple and highly inaccurate integrator that you use. It is pretty easy to do the math and show that.

让我们取一个 1/30 秒的时间跨度.当游戏以 30 FPS 运行时,speed_yy 将只有一次更新,因此 1/30 秒后新位置 y'应该是:

Let's take a single time span of 1/30 seconds. When the game runs at 30 FPS there would be only one update to speed_y and y, so after 1/30 s the new position y' would be:

speed_y' = speed_y - a*dt
y' = y + speed_y'*dt = y + speed_y*dt - a*dt^2

这里 dt 是 1/30 秒的时间增量.

Here dt is the time delta of 1/30 seconds.

当游戏以 60 FPS 运行时,在相同的 1/30 秒内将发生两次更新,时间差是两倍,dt/2:

When the game runs at 60 FPS, in the same 1/30 seconds there would be two updates happening with twice as shorter time delta, dt/2:

// First update
speed_y' = speed_y - a*(dt/2)
y' = y + speed_y'*(dt/2) = y + speed_y*(dt/2) - a*(dt/2)^2
// Second update
speed_y'' = speed_y' - a*(dt/2) = speed_y - a*dt
y'' = y' + speed_y''*(dt/2) = y + speed_y*dt - 3*a*(dt/2)^2

现在比较两个更新后的 y 位置:

Now compare both updated y positions:

  • 在 30 FPS 时为:y + speed_y*dt - a*dt^2
  • 在 60 FPS 时为:y + speed_y*dt - a*(3/4)*dt^2

显然,在 60 FPS 时,y 的新位置会高于 30 FPS 时的位置,因为减去的值更低.

Obviously at 60 FPS the new position of y would be higher than that at 30 FPS because the subtracted value is lower.

这只影响垂直运动.水平速度是恒定的,如果您更新 x 一次或两次以两倍的短时间增量并不重要,因此当您的角色跳跃时,它总是以相同的水平距离移动到它击中的地方地面,无论 FPS 是什么.

This only affects the vertical motion. The horizontal speed is constant and it doesn't matter if you update x once or twice with twice as short time delta, hence when your character jumps it always travels the same horizontal distance to the place where it hits the ground, no matter what the FPS.

要解决这个问题,您必须仔细研究恒定加速度下的运动方程:

To solve this you have to take a closer look at the equation of motion under constant acceleration:

y(t) = y(t=0) + v(t=0)*t - (1/2)*a*t^2

t=0 的选择是任意的,因为物理定律在时间偏移下是不变的,因此可以将 t=0 作为更新间隔的开始然后 t=delta_time 将给出当前更新后的位置.正确的更新算法如下:

The choice of t=0 is arbitrary since laws of physics are invariant under time shifts, so one may take t=0 to be the beginning of the update interval and then t=delta_time would give the position after the current update. The correct update algorithm as follows:

x += speed_x*delta_time;
if (is_in_air) {
   y += (speed_y - 0.5*acceleration*delta_time)*delta_time;
   speed_y -= acceleration*delta_time;
}

请注意,speed_y 应根据运动方程中找到的值在垂直位置之后更新.

Note that speed_y should be updated after the vertical position as per the values found in the equation of motion.

相关文章