Libgdx, physics, acceleration and FPS

2019-05-26 16:40发布

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

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

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 behaviour, the heigh 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;

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

1条回答
叛逆
2楼-- · 2019-05-26 17:07

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.

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

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

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

Now compare both updated y positions:

  • at 30 FPS it is: y + speed_y*dt - a*dt^2
  • at 60 FPS it is: y + speed_y*dt - a*(3/4)*dt^2

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

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

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;
}

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

查看更多
登录 后发表回答