2

I have a ball class with the following variables:

int x,y,width,height;
double velX,velY;

I want to make it so that whenever the ball hits a block, it bounces and it looses some velocity.

//Gravity & movement for the ball
ball.setVelY(ball.getVelY() + 0.2);

ball.setY((int)(ball.getY() + ball.getVelY()));

//Make the ball bounce.
if(ball.getBounds().intersects(block.getBounds()){
     ball.setVelY(ball.getVelY() * -0.7);          
}

I thought this would make the ball bounce slowly until it was barley moving at all (which I would test for and then have the ball stop completely,) but this is not the case. The ball will bounce several times normally with each bounce being smaller than the one before. However, after a few bounces, the ball will stop bouncing lower than previous bounces. Why is this and what should I do to fix it?

phil652
  • 1,484
  • 1
  • 23
  • 48
Oliver
  • 23
  • 2

2 Answers2

8

The problem here is that you are essentially applying small bursts of force to the ball, discretely. Even though you are scaling the momentum down, you are constantly adding this value of 0.2 to the ball's momentum.

As an analogy, what you are doing by periodically applying gravity, is tapping the ball downwards in short bursts, giving it momentum. If you imagine a still basket ball that is on, or slightly above the ground, and you start tapping it rapidly, it's possible to make the ball bounce. However, if you imagine applying a constant downwards force to the ball with your hand (like gravity truly is), then the ball will fail to bounce.

As it's impossible to have your program run in a continuous manner, so to speak, you have to find a way around this. One solution is to simply check for a minimum threshold of momentum upon impact with the floor, and if it is below this threshold then set its momentum to 0, and set it so that it is plush with the surface.

Nicholas Betsworth
  • 1,707
  • 19
  • 24
  • I agree with this assessment. Better to apply the forces in a continuous manner and then check for thresholds (such as 0 or less). This way you can avoid having it have to update periodically and just have it in constant motion until other forces/etc impact it. – Sh4d0wsPlyr May 27 '15 at 17:07
1

The problem might be a numerical one. What you are doing when writting

ball.setVelY(ball.getVelY() + 0.2);
ball.setY(ball.getY() + ball.getVelY());

is integrating a differential equation using the Euler method. In fact, it's a simplification of:

ball.setVelY(ball.getVelY() + g * DeltaTime); // g = 9.8m/s² for earth gravity
ball.setY(ball.getY() + ball.getVelY() * DeltaTime);

where DeltaTime is your integration time step, which you take equal to one, for simplicity.

Unfortunately, the Euler method is only conditionally stable, which means you can end up in situations where the velocity diverges (or this type of never-ending oscillations). In order to recover stability, the best way is to decrease the time step, which in your case means to decrease the velocity, or rather decrease the gravity. Try setting g from 0.2 to 0.05, and increase the frequency of your timer by 4 to verify this.

If you are into maths, you could also take a look at unconditionally stable methods, such as the backward Euler method.

Eric Leibenguth
  • 4,167
  • 3
  • 24
  • 51