问题
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:
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.
回答2:
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).
回答3:
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:
- If you decide to change the increment from 1 you could skip that exact value and cause a bug, but more importantly:
- 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
来源:https://stackoverflow.com/questions/8025599/boolean-flag-not-read-in-while-loop-java