Solution for
Programming Exercise 8.4
THIS PAGE DISCUSSES ONE POSSIBLE SOLUTION to
the following exercise from this on-line
Java textbook.
Exercise 8.4:
For this problem, you will need to use an array of objects. The
objects belong to the class MovingBall, which I have
already written. You can find the source code for this class
in the file MovingBall.java.
A MovingBall represents a circle that has an associated
color, radius, direction, and speed. It is restricted to moving
in a rectangle in the (x,y) plane. It will "bounce back"
when it hits one of the sides of this rectangle. A MovingBall
does not actually move by itself. It's just a collection of data.
You have to call instance methods to tell it to update its position
and to draw itself. The constructor for the MovingBall class
takes the form
new MovingBall(xmin, xmax, ymin, ymax)
where the parameters are integers that specify the limits on the
x and y coordinates of the ball. In this exercise, you
will want balls to bounce off the sides of the applet, so you will
create them with the constructor call "new MovingBall(0, getWidth(),
0, getHeight())". The constructor creates a ball that
initially is colored red, has a radius of 5 pixels, is located at the
center of its range, has a random speed between 4 and 12, and is headed
in a random direction. If ball is a variable of type MovingBall,
then the following methods are available:
- ball.draw(g) -- draw the ball
in a graphics context. The parameter, g, must be of type Graphics.
(The drawing color in g will be changed to the color of the ball.)
- ball.travel() -- change the
(x,y)-coordinates of the ball by an amount equal to its speed.
The ball has a certain direction of motion, and the ball is moved in that
direction. Ordinarily, you will call this once for each frame of
an animation, so the speed is given in terms of "pixels per frame".
Calling this routine does not move the ball on the screen. It just
changes the values of some instance variables in the object.
The next time the object's draw()
method is called, the ball will be drawn in the new position.
- ball.headTowards(x,y) --
change the direction of motion of the ball so that it is headed
towards the point (x,y). This does not affect the speed.
These are the methods that you will need for this exercise. There are
also methods for setting various properties of the ball, such as
ball.setColor(color) for
changing the color and ball.setRadius(radius)
for changing its size. See the source code for more information.
For this exercise, you should create an applet that shows an
animation of 25 balls bouncing around on a black background. Your
applet can be defined as a subclass of
SimpleAnimationApplet2,
which was first introduced in Section 3.7.
The drawFrame() method in your applet should move all the balls
and draw them.
(Alternatively, if you have read Chapter 7, you can program the
animation yourself using a Timer.)
Use an array of type MovingBall[] to hold the 25 balls.
In addition, your applet should implement the MouseListener
and MouseMotionListener interfaces. When the user presses
the mouse or drags the mouse, call each of the ball's
headTowards() methods to make the balls head towards the
mouse's location.
Here is my solution. Try clicking and dragging on the applet:
Discussion
This is actually not a very difficult problem, although it might take
time to get used to working with arrays of objects. An instance variable
of type MovingBall[] is needed to hold the data for the
25 balls. This instance variable can be declared as
MovingBall[] balls;
The array can be created in the applet's init() method with
the command
balls = new MovingBall[25];
However, this just gives an array filled with null values.
There aren't any balls yet. Each of the balls must be created with
a call to the constructor from the MovingBall class:
for (int i = 0; i < 25; i++) {
balls[i] = new MovingBall(0, getSize().width, 0, getSize().height);
}
The array of MovingBalls is used throughout the rest of the
applet. In the drawFrame method, each ball must be moved and
drawn. The i-th ball can be moved by calling its
travel() method with the command "balls[i].travel()".
It can be drawn in the graphics context g by calling its
draw() method with the command balls[i].draw(g);".
To apply these commands to every ball in the array, we need a for
loop
for (int i = 0; i < balls.length; i++) {
balls[i].travel();
balls[i].draw(g);
}
(Using "i < balls.length" instead of "i < 25" in
this loop will make it easier to change the number of balls. It guarantees
that even if the size of the array is changed, the for loop will
still work as written.) Similarly,
in the mousePressed() and mouseDragged() routine,
we need a for loop to tell each ball to head towards the
location of the mouse, (evt.getX(),evt.getY()):
for (int i = 0; i < balls.length; i++) {
balls[i].headTowards(evt.getX(),evt.getY());
}
That's really all there is to it. You might want to try variations
like giving the balls random colors or sizes. This can be done in the
init() method. In my applet, I decided to use applet parameters
to make it possible to customize the applet by specifying the number of
balls and by setting the speed at which the animation plays. In fact,
the applet at the top of this page shows 50 balls instead of the
default 25, and the animation is
playing at 50 milliseconds per frame instead of at the default 100
milliseconds per frame. (The applet on the page of exercises
used the default values.) Recall that applet parameters are specified
in the <applet> tag on the web page. The tag for the
applet at the top of this page is
<applet code="BallisticBalls.class" width=270 height=240>
<param name="frameTime" value="50">
<param name="ballCount" value="50">
</applet>
The param with name "ballCount" specifies the number of
balls in the applet. The param with name "frameTime"
specifies the number of milliseconds to use for each frame of the
animation. You can look at the source code for the applet, below, to see
how I use these params. The method getIntParam() demonstrates
how to get an integer value from an applet param.
The Solution
/*
This applet shows an animation of red balls moving on a black
background. The balls "bounce" off the sides of the applet.
The number of balls can be set as the value of an applet
param with name "ballCount". The default number is 25.
The number of milliseconds per frame can be set as the value of an
applet parameter with name "frameTime". The default is
100 milliseconds. A value of 50 milliseconds will give
a nicer speed.
If the user clicks on the applet, or drags the mouse on
the applet, all the balls head towards the mouse location.
The "balls" are represented by objects of type MovingBall.
This applet depends on the MovingBall class and on the
SimpleAnimationApplet2, which it extends.
*/
import java.awt.*;
import java.awt.event.*;
import java.applet.Applet;
public class BallisticBalls extends SimpleAnimationApplet2
implements MouseListener, MouseMotionListener {
MovingBall[] balls; // An array to hold the balls.
public void init() {
// Initialize the applet. The applet listens for
// mouse events on itself. The balls are created.
// The number of balls and number of milliseconds
// per frame are set from applet parameters (or to
// default values).
addMouseListener(this);
addMouseMotionListener(this);
setMillisecondsPerFrame( getIntParam("frameTime", 100) );
/* Create an array to hold the balls, then create the balls. */
int ballCt = getIntParam("ballCount", 25); // How many balls?
balls = new MovingBall[ ballCt ]; // Create the array
for (int i = 0; i < balls.length; i++) {
// Create each of the ball objects. The parameters specify
// that the balls are restricted to moving within the bounds
// of the applet.
balls[i] = new MovingBall(0, getSize().width, 0, getSize().height);
}
} // end init()
private int getIntParam(String paramName, int defaultValue) {
// Get a non-negative integer applet parameter. This routine
// will read an applet param with the name paramName.
// If the param has a value that is a POSITIVE integer,
// then that value is returned. Otherwise, the defaultValue
// is returned.
String param = getParameter(paramName); // Get param, if any.
// (If there is none, then
// the value is null.)
if (param != null) {
try {
// Try to convert the parameter string to an int.
int N = Integer.parseInt(param);
if (N > 0) // Return the integer only if it is > 0.
return N;
}
catch (NumberFormatException e) {
// The param value is not a legal integer.
}
}
// If we get here, then the param did not exist in the <applet> tag
// or was not a legal integer, or was <= 0. So, return the
// default value that was specified in the function call.
return defaultValue;
} // end getIntParam
public void drawFrame(Graphics g) {
// This method is called by the SimpleAnimationApplet2 framework
// to compute and draw the next frame in the animation. The
// applet is filled with black. Then the balls are moved and
// drawn.
g.setColor(Color.black); // Fill the applet with a black background.
g.fillRect(0, 0, getSize().width, getSize().height);
/* Tell each ball to move. It moves an amount depending on
its current direction and speed, and it will "bounce" off the
side of the applet if necessary. Then the ball is told
to draw itself in the graphics context g.
*/
for (int i = 0; i < balls.length; i++) {
balls[i].travel();
balls[i].draw(g);
}
} // end drawFrame()
public void mousePressed(MouseEvent evt) {
// The user has clicked on the applet. Tell all the
// balls to head towards the location of the mouse.
for (int i = 0; i < balls.length; i++)
balls[i].headTowards(evt.getX(), evt.getY());
}
public void mouseDragged(MouseEvent evt) {
// The user has dragged the mouse on the applet. Tell all
// the balls to head towards the location of the mouse.
for (int i = 0; i < balls.length; i++)
balls[i].headTowards(evt.getX(), evt.getY());
}
public void mouseReleased(MouseEvent evt) { }
public void mouseMoved(MouseEvent evt) { }
public void mouseClicked(MouseEvent evt) { }
public void mouseEntered(MouseEvent evt) { }
public void mouseExited(MouseEvent evt) { }
} // end class BallisticBalls
[ Exercises
| Chapter Index
| Main Index
]