Movement and Bouncing

In lots of games you want to move things around on the screen by simulating aspects of real-life motion.

We've seen in the Driving program how we can use variables, say x and y, to store the position of an object and then use those variables in the paint() method to draw the object in the correct location. In the Driving program, the position is adjusted by a finite state machine so that the car moves in a specified pattern. If we want an object to move steadily in a fixed direction (as though it was sliding across an air-hockey table), then updating the position is much easier. We just store the amount that x is changing in a variable, say dx, and the amount y is changing in another, say dy. In other words, dx and dy form the components of the velocity vector of our object on the screen. By changing these values, we can have the object move in various directions. For instance, dx=5, dy =-5 will move up and to the right, whereas dx=0, dy=3 will move straight down. Assuming we've figured out what values we want for the velocity, updating the position is easy: we just add the velocity component to the position component:

  x = x + dx;  y = y + dy;
This is done once each time through the animation loop.

In general, if you want to bounce off of something, you reflect your velocity vector in a line tangent to the thing you're bouncing off of. While the math for the completely general case is not very bad, the special cases that we care about most often are really easy. If you're bouncing off a vertical barrier, you leave the dy component the same and change the sign of the dx component. If you're bouncing off a horizontal barrier (e.g. the floor), you leave the dx component the same and change the sign of the dy component. You can find these ideas implemented to move the ball around in the Pong demo.

If that's all you did, you would simulate a "perfect" bounce. For instance, a ball bouncing under these rules would bounce forever. In reality, only a percentage of the ball's energy goes into bouncing, so, each time you bounce, the velocity is reduced a little bit. For instance, you might reduce dx and dy to 90% or 40% of their current value, based on how bouncy you wanted your object to be. Thus, bouncing off a floor might look something like:


  dx = 0.9 * dx;  dy = -0.9 * dy;

Notice that we're changing the sign of dy at the same time that we're reducing it.

Your simulation will be more precise if you can record the position and velocity more accurately. For instance, a reduction of a velocity of 2 to 90% of its value should give 1.8. If you're working with integer values, you'll have to settle for 1 or 2 (in which case you haven't reduce it at all!). On the other hand, floating point arithmetic is slower than integer arithmetic, so sometimes you don't want to use it in a game. If you wanted to work with integers, you would probably change the above to


 dx = 9*dx/10; dy = -9*dy/10;

A reasonable compromise is to use single-precision floating point numbers. This means that you declare x,y,dx, and dy to be type float and then you follow constants with the letter f (to show that they aren't the default of double precision). So, we'd have

 dx = 0.9f * dx;  dy = -0.9f * dy;

If you do record the position and velocity in float variables, you'll need to remember to convert them to integers before using them as drawing coordinates. If sx and sy are integer variables used to hold the screen coords, you could say

 sx = (int)x;  sy = (int)y;

to cast the "real" coordinates to pixel locations.

There's another reason why the above formulas won't give a very accurate bounce simulation. This is related to how you know when to bounce. Typically (say to bounce off a floor), you have some boundary specified by a coordinate value (say YMAX = 100). Each time you move your ball, you check if the y coord is greater than or equal to YMAX. If not, there's no problem. If it is greater, then you need to bounce.

If you simply flip the sign on dy and continue (as described above) the ball will bounce, but it won't look quite right (although it will be pretty good). The problem is that if the ball has a y coord greater than YMAX then it has already gone through the floor. We don't really want this. In fact, if y > YMAX, it means that the actual bounce should have occurred sometime during the animation timestep. That is, the ball should be above the floor, not below it.

In fact, it should be above the floor by the precise amount which it is below the floor (assuming that all the energy goes into the bounce). So, we can just figure out how far below the floor it has gone (y - YMAX) and just reset it to the correct value. So, the actual bounce becomes

  dy = -dy;
  y = YMAX - (y - YMAX);
or
  dy = -dy;
  y = 2*YMAX - y;
if we simplify the right side of the second equation.

If we want to be just right for the case where some energy is absorbed, then the "up" portion of our bounce needs to be adjusted by the same factor. Say

  dx = 0.9f * dx;
  dy = -0.9f * dy;
  y = YMAX - 0.9f * (y - YMAX);

Of course, with walls you do similar things with x and dx.


Back to course home page.