CS 124, Spring 2013
Lab 10: Subclasses (and Events)

In this lab, you will work with an API for programming with "sprites." A sprite is a graphical element, like an icon, that can be placed on the screen, and possibly move around on the screen. There are classes to represent several kinds of sprites, and a class to represent the panel -- a rectangular area in a window -- where the sprites are displayed. All these classes are defined in a Java package named sprite. You will create several subclasses of these classes. In addition, the API includes some basic support for responding to keyboard events. That is, you can program responses that will happen when the user presses certain keys on the keyboard.

You should create a lab10 project in Eclipse. Open the folder /classes/cs124/lab10-files in a file browser. Select all four items, copy them, and paste them into the src folder of your lab10 project. You will have files named SpriteDemo1.java and SpriteDemo2.java in the default package and folders named sprite and images. The sprite folder contains the .java files for the package named sprite. (You can also browse the files on-line or download a zip archive of all the files.)

You should not modify any of the .java files that you have just added to the project in any way. You can copy files, if you want, and work on the copies, and you can make new files. But I will not print out or grade any work that you do in files that already exist.

The lab has three exercises. The first two are meant to be fairly quick, and there are detailed instructions for how to do them. The third exercise is longer and open-ended and asks you to design and write a simple game that uses sprites.

Because of the test next week, this lab is due by 10:00 AM on the morning of Tuesday, April 16.

About Sprites and SpritePanel

The sprite API is relatively complex, compared to other things you have worked with in this course. I have generated the documentation in JavaDoc format, which you can browse online. I also did a demonstration in class. However, I include some basic information here.

The two main classes are Sprite.java and SpritePanel.java. But to use these classes, you really have to define subclasses of them. To have actual Sprites, you need to have subclasses of Sprite. I have provided a variety of such subclasses, each representing a different kind of sprite. For example, OvalSprite representing a simple oval-shaped sprite, Bullet is a kind of sprite that can kill other sprites by hitting them, and SimpleGun represents a kind of "gun" that can fire Bullets.

A SpritePanel is where sprites live. A SpritePanel has a method addSprite(s) which takes a sprite, s, and adds it to the panel. The panel keeps a list of sprites that it contains (actually two lists, since Bullet sprites are treated in a special way and are kept in a separate list from other sprites). Sprites can "die", and when they die they are removed from the list and no longer appear in the panel.

A SpritePanel can run an animation. A sprite has a velocity and moves during the animation according to its velocity. However, the animation doesn't start automatically. To start it, you have to call the panel's go() method. This is done, for example, at the end of the main() program in SpriteDemo1.

The other two SpritePanel methods that you are most likely to use are installKeyPress and doKeyPress, which are designed to let the user interact with the program by pressing keys on the keyboard. These methods are discussed in Exercise 3, below.

The Sprite class defines many methods, and you should remember that these can be used with any subclass of Sprite. See Sprite.java for the details. Here are some important instance methods:

Exercise 1: A Simple Sprite Class

(Note: You might want to start Exercise 2 before doing this exercise, to make it easier to test the code that you write for Exercise 1.)

There is already a class OvalSprite. An OvalSprite is drawn as a colored oval. However, there is no class to represent a rectangle. The first exercise is to write such a class. Although you could do that by making a copy of OvalSprite.java, I would like you to work through the process of creating the class from scratch. Working through the instructions for this exercise will help you learn how to create a subclass of Sprite from scratch. You will probably want to take a look at OvalSprite.java before you start, and maybe copy some code from it. (Even if you start with a copy of OvalSprite.java, you will have to add some code to implement step 7, below.)

1. You want to a make a new class named RectSprite in the package sprite. To do this, right-click the sprite package in the Package Explorer view, on the left of the window. Select "New" / "Class" from the pop-up menu. In the dialog box, note that the package for the new class is already filled in as "sprite." When the class has been created, note that it says "package sprite;" at the top, to say that it is in the sprite package.

2. You want RectSprite to be a subclass of Sprite, so edit the first line of the class to read

public class RectSprite extends Sprite {

3. The class needs an instance variable to represent the color of the sprite. Add a private instance variable of type Color. You will get an error, because the Color class has not been imported. Add "import java.awt.Color;" to the file, or let Eclipse do it for you. Note that the import statement comes after the package statement.

4. Write getter and setter methods for the color variable. Better yet, let Eclipse do it for you: From the "Source" menu, select the command "Generate Getters and Setters". You will see a dialog box with a list of variables for which getters and setters can be generated. In this case, the only thing in the list is the color. Check the box next to the variable name, click OK, and the methods will be added to the class.

5. The class could use a constructor. It's not absolute required, but a RectSprite needs a non-zero width and height for it to make sense. Add a constructor that specifies a width and height for the sprite. The width and height properties are actually defined in the sprite class. To set them, you can call the setter methods setSpriteWidth(w) and setSpriteHeight(h). (See the constructor in OvalSprite.java; however, for RectSprite, you don't want to call setUseOvalForContains(true).)

6. One essential method in a sprite is draw, which is responsible for drawing the picture of the sprite. The draw method has to start like:

public class draw(Graphics g) {

You have to draw the sprite with its center at the point whose coordinates are getX() and getY(). These methods are getter methods defined in the Sprite class that give the current location of the sprite. They return double values that have to be type-cast to int before you can use them for drawing. Don't forget to set the drawing color that you want to use for the sprite! Again, see the example in OvalSprite.java. (In this case, you are overriding a method that is already defined in the Sprite class. Again, you can Eclipse to help with this. From the "Source" menu, select "Override/Implement Methods". In the dialog box, select that method that you want to override, and click OK.)

7. Finally, to make things more interesting, make it possible to draw the rectangular sprite with a black border. Whether or not to draw the border should be specified by a private instance variable of type boolean. You should provide getter and setter methods for the variable, and you should use the variable when drawing the sprite: After filling the rectangle, call drawRect to draw the border.

Exercise 2: A Simple Sprite Program

For the second exercise, you will create a simple program that uses sprites. In this case, I suggest that you begin by making a copy of the first demo program, SpriteDemo1.java. You could call the copy, for example, FirstSprites.

Note that the class is defined as a subclass of SpritePanel. That is, an object created from the class is a rectangular area in a window that can hold and display sprites and has methods for managing the sprites that it contains. (The class also has a main() program. The main program is static and so is not any part of any object created from the class. This would probably be considered poor style by most people -- the main program should probably be in another class altogether. But having a main() in the class makes it possible to run the class as a program.

The goal of this exercise is to create a program that will allow the user to add sprites to the window by pressing keys on the keyboard. In particular, when the user presses the "R" key, the program should add a RectSprite to the window. The new sprite should have a random velocity. You can decide what its starting position should be. You will want to look at some of the code in the sample programs to see how to make a sprite and add it to the panel.

Pressing the "C" key should remove all sprites from the window. You can do that very easily by calling the clear() method, which is defined in class SpritePanel. You should program a few other keys, as well. You could add some other kinds of sprites, for example. (Try adding Explosion sprites at random positions.) Here are some more detailed instructions:

1. First, delete most of the code from the constructor. In the demo program, the constructor added some sprites to the panel when the panel is first created. You want to start with an empty panel and add sprites only when the user presses the appropriate keys.

2. You will need some "installKeyPress" commands in the constructor. For a key to have any effect, you must install it with this command. For example, to activate the "R" key, you need to say

installKeyPress("R");

This method is defined in the SpritePanel class. See the documentation for the method for more information.

3. Finally, you have to modify the doKeyPress method to program the responses to the "R", "C", and other keys. Note that you don't call this method anywhere in your program. It will be called by SpritePanel when the user presses a key that has been installed with installKeyPress(). When you write this method, your job is to say what will happen when the user presses the key.

Exercise 3:

For the third exercise, you should program an interactive game using sprites. You can begin the program in the same way that you started Exercise 2, by copying SpriteDemo1.java. Most likely the game will include a gun that the user can fire and sprites for the user to shoot at. You can make something very similar to SpriteDemo3, but for full credit, you should make some changes or add some new features. (I didn't give you the source code for SpriteDemo3, but there is a .jar file in /classes/cs124 that you can run.)

To have a gun, you want to add a sprite of type SimpleGun to the panel. You will want to do this in the constructor, since the gun is a permanent part of the game. A gun is already programed with the ability to fire bullets that can kill other sprites; you just have to call its fire() method. (If the variable gun refers to the gun, that would really mean calling gun.fire().) To change the direction that the gun points, you can use its getAngle() method to get the current angle, and then use its setAngle method to point it in a different direction. In SpriteDemo3, this is done in response to the left and right arrow keys.

SimpleDemo3 also adds a bunch of sprites to the panel in the constructor to serve as sprites. They are given random positions and random horizontal velocities. Their vertical velocities are zero.

There are many ways that you could change or enhance the game, and you should try to be creative if you can come up with ideas of your own. You might even create an entirely new kind of sprite to use in the game. (However, not everything that you might want to do will be possible with the sprite API.) Here are some ideas: