Before you start, fill out a "Project Plan" in PSP
with estimates of how long the program will be, how many defects you'll
encounter, and how long it'll take you. (You will not be graded on how
accurate your estimates are, but you are expected to make some
kind of reasonable estimate.)
As you work on the assignment,
keep track of all the defects you encounter,
and your time use, using the
PSP forms
(click on "Input" under "Defect Removal Data" or "Time Management Data"
respectively).
Write an Applet that displays a number of rectangular boxes
and circular balls on the screen. Each box and each ball should have its own
location and velocity. There should be at least the following controls:
- A "create ball" button that adds one more ball to the screen
- A "create box" button that adds one more box to the screen
- A "move" button that moves all of the balls and boxes by
their respective velocities (e.g. if a particular ball's
velocity were (3,2), it would move by 3 pixels to the right and 2
pixels down)
- Four TextFields labelled "x", "y", "dx", and "dy" in which the
user can type numbers; whenever a new ball or box is created using the
above buttons, it should be set up using the contents of these TextFields.
If the contents of any of the TextFields isn't a number, display some
kind of error message and don't create anything.
- Optional: a "delete" button and another
TextField labelled "which to delete", in which the user can type a number;
when the "delete" button is clicked, it deletes the ball or box whose
number is specified in the TextField. If the contents of the
TextField aren't a number, or are a number less than 0 or greater than
the index of the last ball or box, display some kind of error message
and don't delete anything.
- Optional: a "move continuously" button.
Normally, things move only in steps, when you click the "move" button.
When you click the "move continuously" button, things start moving
continuously until the next time you click the "move continuously"
button (which should probably change its label to "move in
steps").
The balls and boxes should move within a Canvas, so they don't interfere
with the controls. Whenever a ball or box approaches the edge of the
Canvas (top, bottom, left, or right), it should bounce off.
Hints:
- Balls and Boxes have a lot in common, but they're not exactly the
same. Treat them like Guitar and Keyboard from homework 3, as two
subclasses of an abstract class Shape. Remember: whenever you find
yourself writing the same code in the Ball and Box classes, it
probably belongs in the Shape class instead.
- The biggest difference between a Ball and a Box is how they are
drawn on the screen: one is circular, the other rectangular. So give
each of them (and the abstract class Shape) a "paint" method.
- Since your Applet will need to keep track of a bunch of Shapes,
it could contain an array of them, like the Inventory class in homework 3.
The Applet would then have a bunch of methods related to adding and
deleting Shapes.
But I like each of my classes to do only one job, so I would write a
separate class named ShapeList, looking a lot like Inventory
from homework 3: all the methods concerned with how many Shapes there
are would then go in this method, leaving the Applet concerned only
with setting up GUI components and stuff like that. The Applet would
have a single variable of type ShapeList, and when the Canvas needs to
paint itself, it'll simply ask the ShapeList to call "paint" on
each of its Shapes. I would suggest a method named
"paintAll()" for this purpose.
- To detect when one of your shapes is approaching the edge of the
Canvas, use the "getSize()" method of the Canvas. This will return a
Dimension, which comprises two ints named "height" and "width".
- If your shape's x-coordinate becomes bigger than "width", it has
passed the right edge of the Canvas, so to bounce off, you need to
replace the x component of its velocity by its negative. Likewise, if
the x-coordinate becomes less than 0, it has passed the left edge of
the Canvas, so you need to negate the x component of the velocity
(making it positive). And similarly for the y coordinates. All of
this checking needs to be done whenever the shape moves, so you might
want to put it inside (or called from) the "move()" method.
- The "repaint()" method you've seen invalidates the
whole window, or the whole Canvas, or whatever. To avoid flickering,
it's better to use a
different version of the repaint() method, which invalidates only
a small rectangular portion of the screen. Whenever a shape moves, it
should "repaint" the rectangle where it was (so it'll be erased from
there) and the rectangle it has moved to (so it'll be drawn
there).
- This is a big assignment. You won't be able to do it all at once;
instead, plan out a sequence of versions before you start,
specifying what features each one will have, and when you expect to
have it finished. For example,
- An Applet that draws a box on the screen.
- The box moves each time the paint() method is called.
- Make the Box a separate class with its own paint() method and
constructor; the Applet has an instance variable of type Box and calls
its paint() method from within the Applet's paint() method.
- Add a move() method to the Box class; test it by calling the
method from BlueJ and examining the resulting Box.
- Add a bunch of Labels, TextFields, and Buttons that don't do
anything.
- Use a BorderLayout to place the Buttons and TextFields
appropriately.
- Add a Canvas; move the Applet's paint() method into the Canvas.
- Add a second Box with a different location and velocity.
- Define a ShapeList class that holds the two Boxes and has a
"paintAll()" method and a "moveAll()" method.
- Make the "move" button invoke the "moveAll()" method of the
ShapeList.
- Change the ShapeList class to hold an array of
Boxes instead of two separate instance variables (but still
initialize this array to have two Boxes).
- Write an "add" method for the ShapeList class; test it by
calling the method from BlueJ and examining the resulting ShapeList.
- Have the "create box" button invoke this "add" method on a
newly-created Box with fixed coordinates and velocity.
- Have the "create box" button look at the TextFields to
determine the initial coordinates and velocity of the new Box.
- Define a Shape class, with Box as a subclass. Wherever the Box
class does something that Ball will need to do in the same way, move
that code up into Shape.
- Change the ShapeList class to maintain an array of Shapes
instead of Boxes.
- Define a Ball class, another subclass of Shape. Change the
constructor for ShapeList so that, by default, it creates a Ball and
a Box.
- Make the "create ball" button work, like the "create box"
button.
- Make the balls and boxes bounce off the walls correctly.
Of course, this isn't the only possible order of features; choose a
sequence of versions that makes sense to you. The point is that each
version requires only a small addition to the previous one, and each
one will be tested and debugged before you start on the next.
-
How to turn this in: Once you've got all of this working,
"WinZip" the entire folder into a single file and
send me an
e-mail, attaching this ZIP file.
If you have any comments about problems you encountered in writing the
program, or things you learned, put these in the body of the e-mail.