3
votes

As far as I understand, there's a pretty standard way to implement gravity, which is pretty much the real deal; adding a number (say, 9.8) to an object's downward vertical velocity with each time step.

However, this simple math has led to an issue of "infinite bounce" in my program (and apparently others). The simple test case so far has a ball dropping straight down, and hitting the "floor". On collision, the ball's vector is deflected and reduced by 1/4 (a placeholder Coefficient of restitution). On every time step, the gravity value (around 2 in my case) is added to the vector. As a result, the ball bounces, and then bounces lower, and lower... and then instead of truly stopping, or even visibly stopping (the real goal), it jitters up and down on the bottom of the screen. Debugging readouts show that its speed never drops below 2 for more than a couple frames, because that constant just keeps getting added and cancelled and added again indefinitely.

Now, understanding why isn't the hard part. It's exactly what I feared from the start, I just figured there was some mathematical magic I was overlooking since no one ever actually mentions such an issue when explaining the math. But - since no one ever discusses it - that does leave me wondering, what is the "typical" way to go about fixing it?

EDIT: After considerable work, I have determined that using separate acceleration values alone won't fix the problem - it will still always try to add some constant fraction of gravity. Constant time step means constant acceleration; constant acceleration means constant velocity increase. The coefficient of restitution on bounce will cause the velocity to reduce to a point, and negate acceleration, but acceleration will start over from 0. Like so:

  1. Acceleration starts at 0, velocity at y.
  2. Acceleration incremented by (grav * timestep).
  3. Velocity incremented by acceleration.
  4. Reiterate 2-3 until collision with floor.
  5. Acceleration is now back at 0.
  6. Velocity vector reflected accordingly, then multiplied by CoR.
  7. Reiterate 2-3 as velocity goes from negative, to 0, to positive again.
  8. Reiterate 2-7, with each bounce conserving less momentum than the last.
  9. Bounces are now extremely small.
  10. Velocity is now less than (grav * timestep).
  11. Collision with floor sets acceleration back at 0.
  12. Acceleration increased by (grav * timestep) again.
  13. Velocity is increased by acceleration - now enough to swing from negative to positive all at once.
  14. Repeat 11-13 ad infinitum.

Now, the overall problem is not that velocity will never equal 0. That is expected. But what is also expected, is an infinitely decreasing number. With a Coefficient of Restitution set at 0.5, the resulting bounce velocity should be half that of the last, progressively decreasing until it can be discarded as "stopped". By introducing pure constant addition - be it adding directly to velocity, or adding it to another value that gets added to velocity - this problem is incurred. I need to know how to solve that, specifically.

2
Why would you add the gravitational constant to the velocity? It should be applied to the acceleration. - William Pursell
@WilliamPursell At the moment, there is no "acceleration" value. The ball wants to be at x,y at the end of the time step, and gravity influences where that y is. I'll look into how feasible a true acceleration value is. - DigitalMan
This is due to deficiency in your integration scheme. When the ball is too close to the ground, the addition to the velocity must be a fraction of the whole acceleration value, because the ball moves down for less than a whole timestep before it hits the floor. - Hristo Iliev
BTW, the motion is truly infinite - though the ball is losing energy after each bounce, the energy would reach 0 (i.e. the ball would stop) only in the limit of infinite number of bounces. - Hristo Iliev
Just letting you know, the method you describe (Euler's Method) for numerically approximation actually isn't the standard, because it actually isn't that accurate..if you look into the calculus of it all you'll see that it actually is a pretty bad way to approximate differential equations (which is what gravitational acceleration is). The "standard" way (in industry) is Verlet Integration, which gives you an error that shrinks as the fourth power of your timestep, because it deals with velocities and accelerations in a way that gets rid of a lot of the numerical innaccuraces of euler's method - Justin L.

2 Answers

1
votes

Just dealt with the same problem.

Here is the code that fixed it for me:

if (cat.y + cat.height >= ground.y)    // if the cat has hit the ground
{
    cat.y = ground.y - cat.height;    // reset to the bottom
    cat.vector.y = Math.round(COR * -cat.vector.y);    // might want to round down
}

The important part here is the rounding.

0
votes

To solve it the only thing you have to do is when the ball hits the ground reverse the vertical velocity and place the ball on the barrier so that the ball will lock on to the ground because the 9.8 / 4 upwards velocity won't be enough to 'unlock' it and set it in another bounce.