Monday, August 9, 2010

Program to Draw an Animated Bouncing Ball

As I learn to code, programmer friends emphasize that I should break a problem down into chunks that I solve sequentially. It helps me think clearly to focus on one goal at a time.

For example, a recent question asked me to create a ball that bounces within the graphics window, like this.

The 3 main parts of this problem, once you draw the ball, are:

1) Get the ball to MOVE.
2) Get the ball to STOP at the edge of the graphics window.
3) Get the ball to BOUNCE to the next wall, over and over.

Here is how I tackled them:

Step 1. Get the ball to MOVE:
When I started the problem, I just wanted to make a ball on the screen and get it to move in the direction I told it to. It would start moving at an x=y diagonal. I wrote a ‘while’ loop that says, “As long as we’re in this loop, move the ball one pixel to the left (dx) and one pixel down (dy).”

At this point, I didn’t know whether I’d have to tell the loop to make the ball stop moving when it got to the edge of the window or whether it would automatically do so. (Silly me). As it turns out, it really goes on forever! I ran the app to see what would happen, and the ball, once it reached the end of the window, kept going, apparently forever. (See for yourself.) That meant I next had to figure out how to detect the edge of the window and make the ball stop.

Also, the textbook problem required that the ball start off in the middle of the screen, though in my screencast you’ll notice that I had it starting at the top-left corner. This is because, for the Java graphics library, (0,0) is the top-left corner, so it’s easy to start the ball there, whereas placing it in the center requires a trivial bit of algebra that I knew I’d be able to do later. I just wanted to make the ball quickly and confirm that my ‘while’ loop could get the ball to move.

public class BounceBall extends GraphicsProgram {
    public void run() {
   
//First make the ball...    
   GOval ball = new GOval (0, 0, DIAMETER, DIAMETER);
        ball.setFilled(true);
        add(ball);
        
        double dx = 1;
        double dy = 1;
 
        while(true) {
            ball.move(dx, dy);
            pause(PAUSE_TIME);
            
        }
//Private Constants   
    private static final int DIAMETER = 40;
    private static final int PAUSE_TIME = 20;
    }

2) Get the ball to STOP at the edge of the graphics window.

Now I needed to figure out how to make my program “know” when it’s the end of the window, so it could make the ball stop. I wanted the program to say, “When X coordinate of the ball equals the width of the window, or when Y equals the height of the window, stop!” (To be more precise, the X coordinate should actually be the width of the window MINUS the diameter of the ball, so that the ball doesn’t sink past the edge of the window before it bounces each time). 


At first I was stumped, because I couldn’t think of a way to keep track of the x and y coordinates of the ball. After all, in Java, to move the ball, you just declare variables “dx” and “dy”, which tell you how much to move the ball by; you don’t specify what the new coordinates are. After chatting with my friend Emmett, I realized that you could just declare variables “x” and “y” to equal the x and y coordinates of the ball, which you alter, by adding dx and dy to them, respectively, in every iteration of the loop. Indexing x and y lets you check the coordinates, even if it’s not necessary for the “move” command itself. Seems obvious now, so thanks Emmett :) Also in this stage, I centered the ball’s starting position.






public void run() {

//First you make the ball-- centered now
 int x = (getWidth()-DIAMETER)/2; 
 int y = (getHeight()-DIAMETER)/2;    
   
 GOval ball = new GOval (x, y, DIAMETER, DIAMETER); 
 ball.setFilled(true);
 add(ball); 
 
//Then you make it move
 int dx = 1; 
 int dy = 1; 

 while(true) {  
  ball.move(dx, dy);  
  pause(PAUSE_TIME);  
  x += dx; //changing x and y to check coordinates 
  y += dy; //against graphics window    
  
  if (x >= getWidth()-DIAMETER) {    
   break;
      }  
  if (y >= getHeight()+DIAMETER) { 
   break;
      } 
  if (x == 0) {
   break;
     }  
   if (y == 0) {
   break;
     }
}

3) Getting the ball to BOUNCE

Getting the ball to bounce is just a matter of switching the dx or dy variable to its own negative once we detect that the ball hit a wall. (I drew the ball’s path on a notepad before I attempted coding to think this through.) For example, if the ball is moving down and to the right and hits the bottom edge, it will start going upwards, but its horizontal direction will still be to the right. In that case, dy will switch to -dy, but dx won’t change.

What this looks like in terms of coding is I made “if” statements that say, “If we hit the top or bottom of the wall (aka if the y coordinate of the ball is zero or the height of the window), then change dy to -dy. If we hit the right or left side of the window (aka if the x coordinate is zero or the width of the window) then change dx to -dx. This can go on indefinitely.
while(true) {
 ball.move(dx, dy);
    pause(PAUSE_TIME);            
/*Reset the variables x and y at each iteration
 so can check them against window boundaries*/     
    x += dx;
    y += dy;
            
    if (x >= getWidth()-DIAMETER) {
        dx=-dx;
        dy=dy;
            }
    if (y >= getHeight()-DIAMETER) { 
        dx=dx;
        dy=-dy;
            }
    if (x == 0) { 
        dx=-dx;
        dy=dy;
            }
    if (y == 0) {
        dx=dx;
        dy=-dy;
            }
        }


Something to think about is: What will happen if the ball hits a corner? If it hits the top-left corner, will it bounce to straight right or straight down? Answer: it depends on the order you write your “if” statements in. My particular code checks for hitting the left before it checks for the top, so when the ball hits top-left it will bounce horizontally.