Due: Friday, March 3rd, 5:00P.M.
ball is nullrun(), ball is initialized to null. Then, we pass it to setupBall(); therefore, we make a copy of the address inside ball (which is null) and give that to setupBall(). setupBall() then sets ball equal to a new GOval:
private void setupBall(GOval ball) {
ball = new GOval(BALL_RADIUS * 2, BALL_RADIUS * 2);
...
}
The problem is that this overwrites the address given to setupBall() with its own address, so it no longer has any relationship with the version of ball from its caller. Thus, the GOval created can be referenced only within setupBall, so when we go back to run(), ball is still null:
GOval ball = null;
...
setupLabel();
setupBall(ball);
// Ball is still null!
while (true) {
ball.move(dx, dy);
...
}
Here's a diagram of the stack and heap to visualize what's going on:
ball before passing it to setupBall(), or make ball an instance variable and don't even bother passing it as a parameter.
dx and dy incorrectly updatedcheckForCollisions() is supposed to change dx and dy, but we are only passing copies of the two variables from run():
double dx = rgen.nextDouble(MIN_DX, MAX_DX);
double dy = rgen.nextDouble(MIN_DY, MAX_DY);
...
while (true) {
ball.move(dx, dy);
checkForCollisions(ball, dx, dy);
...
}
In other words, because dx and dy are primitives, checkForCollisions() will have its own copies of them, and any changes we make to them in checkForCollisions() will not affect the original variables in run().
dx and dy instance variables and don't even bother passing them as arguments. Not every variable should be an instance variable, of course. But as a rule of thumb, any variable that will be changed over the course of multiple methods can be an instance variable.
int, double, boolean, or other primitive, youll need to return that value from the method. However, you can only return one value from a method. As an alternative solution, we could have split checkForCollisions() into two separate methods checkForXCollision() and checkForYCollision() that each return their updated values.
getRandomNewColor() independently:
ball.setColor(getRandomNewColor(ball.getColor())); text.setColor(getRandomNewColor(ball.getColor()));Thus, the two randomly-generated colors will likely differ from one another.
Color newColor = getRandomNewColor(ball.getColor()); ball.setColor(newColor); text.setColor(newColor);
GLabel not horizontally centered
double x = (getWidth() / 2.0) - (text.getWidth() / 2.0);
double y = getHeight() - TEXT_HEIGHT;
text.setLocation(x,y);
text.setFont(new Font("Arial", Font.BOLD, 32));
As a result, the location is based off of the smaller, default size, not the larger font size.
GLabel first and only afterwards set the location.
ball.move() calls from checkForCollisions(). These aren't buggy! What they're doing is moving the ball away from the wall so that it doesn't go offscreen when bouncing. If you remove them, this alters the bouncing behavior slightly and gives you a modified secret code G9Y8B-O1G9.
RandomGenerator for the purposes of this assignment (not due to debugging this program). Because we set the "seed" of the RandomGenerator (which means that each time you run your program you'll get the same series of random values), you must generate all random numbers after the rgen.setSeed(106 + 'A') in run(). Some people, when making their dx and dy instance variables, also initialized them to random values outside of run as follows:
private double dx = rgen.nextDouble(MIN_DX, MAX_DX); private double dy = rgen.nextDouble(MIN_DY, MAX_DY);If you generate random values outside of
run(), they will be generated before run() is called (and thus before the seed is set) so you will get actual random values that will change every time. The solution is to initialize dx and dy inside of run():
private double dx;
private double dy;
public void run() {
rgen.setSeed(106 + 'A');
GOval ball = null;
dx = rgen.nextDouble(MIN_DX, MAX_DX);
dy = rgen.nextDouble(MIN_DY, MAX_DY);
...
}