Write an applet, Bugs, that simulates these erstwhile kitchens. Wherever you double-click, a bug appears and moves toward the top of the window. If you single-click on top of a bug, the bug disappears. (If the location of a single-click is over more than one bug, then all the bugs under the click location disappear.) The applet window should display the number of bugs at all times. You can play with my implementation:
Note also that the action stops when the mouse leaves the applet window, and it resumes when the mouse enters the applet window.
The applet window should be 500 x 500 pixels, with a pink background.
(Use Color.pink.)
Wherever you double-click gives the upper left corner of the image of a bug that appears and moves up toward the top of the window. When you single-click, all bugs whose images are under the mouse location are terminated. That is, they no longer exist.
Your applet should be able to accommodate up to 500 different bugs at one time. Note that once a bug moves off the top of the applet window, it no longer exists: it doesn't contribute toward the count of bugs, and your program should no longer keep track of it. Each bug should move 3 pixels toward the top of the applet window every 100 milliseconds.
The image of the bug is at bug0.gif. It looks like this:
This image is 33 pixels wide and 50 pixels high. In order to run the applet, you will need to put this image into the project that contains your .java files. Just drag the image onto the src or (default package) icons or names, the same as you do for your .java files. Its name will appear after your .java files.
The Applet class has a method, getImage,
that you will use to read the image. Because this method is in the
Applet class, you can call it in any of the methods
within your class that extends Applet. For example, my
implementation calls getImage in the init
method.
getImage takes two parameters. The first is a reference
to a URL object. Don't worry about what a
URL object is. You'll use a call to the parameterless
method getCodeBase as the first actual parameter in your
call to getImage; getCodeBase returns just
what you need. The second parameter to getImage is a
reference to a String containing the name of the image
file you want to read; you'll use "bug0.gif" as this
parameter. getImage returns a reference to an
Image object. You'll use this Image object
to draw the image.
For example, you could write the following in the init
method of your applet:
Once you have a reference to an Image, you display it
with the Graphics method drawImage. This
method takes four parameters: a reference to the Image to
display, the x-coordinate of the upper left corner of where the
image is to appear, the y-coordinate of the upper left corner,
and a reference to the Applet object in which it will be
drawn. (I have no idea why this last parameter is necessary.) If you
have the following declarations, here's how you would display an
image:
Bug classBug.
Each Bug object has only one instance variable, a
reference to a Point, giving the upper left corner of
where the Bug's image is currently displayed.
In addition to the instance variable, I defined several static variables. Recall that there is only one version of a static variable, and it is shared among all instances of the class.
int giving the speed at which each
Bug moves.
ints for the image's width (33) and height
(50).
Image that is drawn for every
Bug. Of course, this Image is drawn
at different locations for the various Bug
objects, but it's the same Image.
Applet that is running.
init method of the applet itself calls
this static method, passing it a reference to an Image
that it reads, and a reference to the applet itself (think:
this). Why bother? I needed these two references within
the method that draws a Bug in order to call
drawImage. I suppose I could have passed them around as
parameters, but I know that it's going to be the same
Image and the same applet the whole time. Why not just
get them once and for all at the start and use them as needed?
The constructor for my Bug class just takes the
Bug's initial position and saves it in the instance
variable.
My Bug class has a method that reduces the
y-coordinate by subtracting the speed, and it also returns a
boolean indicating whether any part of this image is
still visible. That's easy to compute: we know the
y-coordinate of the upper left corner, and we know the height
of the image, and we just want to know whether the y-coordinate
of the bottom of the image is nonnegative.
My Bug class also has a method that just determines
whether a Point, given as a parameter (technically, a
reference to the Point, but you know that...) is within
the image of the Bug. Again, this is pretty easy.
You've got the Point, you've got the upper left corner of
the image, and you've got the width and height. To be within the
image, the Point has to be
Swarm classSwarm.
My Swarm class has two instance variables: an array of
references to Bug objects, and a count of how many bugs
there currently are. If there are n bugs, then the first
n array entries reference the appropriate Bug
objects, and the rest are null.
Although you could use an ArrayList instead
of an array, you are required to use an array—not an
ArrayList—of references to Bug. This
array must follow the rule above: If there are n bugs, then the
first n array entries reference the appropriate
Bug objects, and the rest are
null.
Here's a brief description of the methods of my Swarm
class:
Bug object draw
itself.
Point,
creates a Bug at that point and adds it to the
array, updating the count. If the array is full, however, this
method does nothing. (You certainly don't want to add anything
to a full array.)
Bug. It does so by
copying the last "real" entry in the array into the entry
referencing the Bug that you want to terminate,
sticking a null into the last "real" array entry,
and decrementing the count of bugs. This is a much better way
than the "obvious" way of moving up by one slot each of the
array entries following the terminated Bug. If
you don't understand how it works, draw a picture. Your
section leader should cover this idea in section this week.
Bug objects,
terminating any that have moved off the applet window.
Bug objects whose
image contains a Point (given as a parameter).
Bugs classBugs class as the applet. You know how
to write most of it, and I've given you some hints above. What you
don't yet know is how to distinguish single-clicks from double-clicks.
You will need to do so in your mouseClicked method.
Given a reference, say event, to a
MouseEvent, you can call the MouseEvent
method getClickCount to get how many mouse clicks
occurred in the event. The call event.getClickCount()
returns the number of clicks as an int. All you need to
do is to terminate bugs whose image contains the mouse position upon
getting one click, and to add a new bug at the mouse position upon
getting two clicks.
There is one slight subtlety. It turns out that a double-click event is always preceded by a single-click event. How do you know not to terminate bugs when a double-click occurs? You don't. We'll finesse this problem by calling it a feature rather than—I've painted myself into a corner here—a bug. Don't feel bad for the bugs just because we might terminate some in order to create one. Remember how many insects there are in the world—enough that we would need 64 bits to count them.
Bug
class and immediately test it. To test it, you will have to
write a small driver applet that creates some Bug objects
and runs the Bug methods on them. (Remember that
"driver" is not synonymous with "main method." Rather, a driver is a
program that exists just to exercise some other piece of code. Here,
the driver I am suggesting exercises your Bug class.)
Make sure that the bugs draw and move correctly. Test to verify that
your code correctly determines whether a given Point is
within a Bug's image.
Next implement the Swarm class and test it. Make sure
that you can add bugs, move bugs, draw bugs, and that bugs are
terminated correctly when they run off the top of the applet or when
they are under a given point. (It may help to reduce the maximum
number of bugs to a small enough value that testing is easy. Yay for
final variables!)
Next implement the init, paint, and
mouseClicked methods. Don't worry about the timer yet.
Make sure that bugs are added and drawn when you click the mouse.
Finally, add the Timer object and then
actionPerformed, mouseEntered, and
mouseExited methods.
If you hand in any extra credit, make sure to hand it in as a program separate from the basic part of this lab assignment. That way, if you make any errors that are due solely to the extra-credit part, you won't lose points for the basic part of the assignment.
After the last image (bug7.gif), you can cycle back to the first image (bug0.gif). (If you're astute, you'll notice that bug1.gif and bug3.gif are the same image, and bug5.gif and bug7.gif are the same image. That won't help you, however.)
Clearly, you'll need to read in an array of Image
objects. Each Bug object will have to keep track of
which of these images it's currently displaying. They all have the
same size: 33 pixels wide and 50 pixels high.
Bug class, rather than a static variable.
Here's my applet with both of the above extra-credit features:
CS 5 Lab Assignment #2
Your blitz with Subject line "YYYYYY" has been received by the cs5-xxxxxx account.where YYYYYY is replaced by the "Subject:" line of your Blitz, and xxxxxx is your section leader's name.
CS 5 Lab Assignment #2 v2The "v2" will indicate that it's the second version. And if you need to go to a third version, use v3. And if you need to go to a fourth version, then you're sending too many versions, and you need to think more carefully before Blitzing!!
Bear in mind that our autoreply system will not send an automatic reply twice within any 10-minute span.
It is your responsibility to round up the envelope before the assignment is due.
final
variables. No public instance variables. Correct use of
instance, static, and local variables. Correct constructors.
Correct object usage. No references to Bug
objects that have been terminated. Good decomposition into
objects and methods. Proper use of parameters. Source code
formatting. Comments!