0

I've written a program to bounce a ball around a screen. The program as written below does not work (the ball just moves off screen).

However if I declare the boolean variables atHorizontalEdge and atVerticalEdge inside the while loop, it seems to work. Why is that the case? As the booleans are defined for the entire run() method, shouldn't it be callable by the while loop even though its outside the while loop?

import acm.program.*;
import acm.graphics.*;
import java.awt.*;

public class BouncingBallv3 extends GraphicsProgram {
    public void run() {

        double x = (getWidth() - BALL_SIZE)/2 ;  //sets the starting position of ball at center
        double y = (getHeight() - BALL_SIZE)/2 ;


        GOval ball = new GOval (x, y, BALL_SIZE, BALL_SIZE ); // creates a red ball at center of screen
        ball.setFilled(true);
        ball.setColor(Color.red);
        add (ball);

        double dx = 1; //increments by which the ball moves
        double dy = 1;

        //declares boolean variables to test if ball position is at an edge
        boolean atHorizontalEdge =  (ball.getX() == getWidth() - BALL_SIZE) || ball.getX() == 0 ; 
        boolean atVerticalEdge = (ball.getY() == getHeight() - BALL_SIZE) || ball.getY() == 0 ;

        /* while loop keeps the ball moving in direction dx,dy
         * if ball reaches a position at any edge, the direction dx or dy changes
         */

        while (true) {

            if (atHorizontalEdge) {          //changes direction of ball if it hits a left/right wall
                dx = -dx;
            } else if (atVerticalEdge) {     //changes direction of ball if it hits a top/bottom wall
                dy = -dy;
            }
                ball.move(dx,dy); 
                pause (PAUSE_TIME);

        }



    }



    private static final double BALL_SIZE = 50;
    private static final int PAUSE_TIME = 5;
}
  • 1
    I just saw you're comparing `double`s with `==`. Read this: [What Every Computer Scientist Should Know About Floating-Point Arithmetic](http://download.oracle.com/docs/cd/E19957-01/806-3568/ncg_goldberg.html). I also updated my post to include a note about that. – AusCBloke Nov 06 '11 at 06:59

3 Answers3

4

The issue is not that the declaration of the booleans is outside the while loop. It is that you are checking for your boundraies outside the while loop. Because of this, your condition is never updated and it only checks for the original state of the ball.

NickLH
  • 2,643
  • 17
  • 28
0

You should update the atHorizontalEdge and atVerticalEdge in the loop body after each iteration, I think.


UPDATE:

The while-loop body should be like this, ` //declares boolean variables to test if ball position is at an edge boolean atHorizontalEdge = false; boolean atVerticalEdge = false;

    /* while loop keeps the ball moving in direction dx,dy
     * if ball reaches a position at any edge, the direction dx or dy changes
     */

    while (true) {
        atHorizontalEdge = (ball.getX() == getWidth() - BALL_SIZE) || ball.getX() == 0;
        atVerticalEdge = (ball.getY() == getHeight() - BALL_SIZE) || ball.getY() == 0;

        if (atHorizontalEdge) {          //changes direction of ball if it hits a left/right wall
            dx = -dx;
        } else if (atVerticalEdge) {     //changes direction of ball if it hits a top/bottom wall
            dy = -dy;
        }
            ball.move(dx,dy); 
            pause (PAUSE_TIME);

    }`

The reason why it works if you define atHorizontalEdge and atVerticalEdge inside loop is because each iteration these two variables are re-computed (i.e. updated).

Summer_More_More_Tea
  • 12,740
  • 12
  • 51
  • 83
0

atHorizontalEdge and atVerticalEdge can be declared inside or outside the while loop, that's not important.

The important thing is, the following is calculated only once, before the loop starts:

atHorizontalEdge =  (ball.getX() == getWidth() - BALL_SIZE) || ball.getX() == 0 ; 
atVerticalEdge = (ball.getY() == getHeight() - BALL_SIZE) || ball.getY() == 0 ;

Therefore atHorizontalEdge and atVerticalEdge will each have the same value from the start to the end of your run method (which is forever).

You obviously want the above two lines to be executed at every iteration in your loop, since they're not going to update by themselves...

while (true) {
   atHorizontalEdge =  (ball.getX() == getWidth() - BALL_SIZE) || ball.getX() == 0 ; 
   atVerticalEdge = (ball.getY() == getHeight() - BALL_SIZE) || ball.getY() == 0 ;
   ...
}


EDIT: Also, it'd be a better idea to check if the x and y were greater than or equal to the width/height, and less than or equal to 0 for 2 reasons:

  1. If you decide to change the increment from 1 you could skip that exact value and cause a bug, but more importantly:
  2. You're using a double and the floating-point representation of the number might not be exactly what you're comparing it to, so == can cause bugs, and the ball might go past the edge and keep going.

ie. ball.getX() >= getWidth() ... ball.getX() <= 0

What Every Computer Scientist Should Know About Floating-Point Arithmetic

AusCBloke
  • 18,014
  • 6
  • 40
  • 44