CS 51 Laboratory # 10
Centipede
Due: December 8th at Midnight
(Design due: November 24th, 11am)
Centipede - with its colorful mushroom patch, tenacious centipedes, bouncing spiders, fleas and scorpions - was one of the earliest and most popular video arcade games. It was brought to life by Atari in 1981 and has remained relatively popular over the years. (One of the 55,000 game units built by Atari recently sold for several thousand dollars on EBay. Sadly, the Dean denied our request for discretionary funds to place a higher bid...) For Test Program 2, you will write a version of "Centipede." We have simplified the game somewhat to make the assignment more manageable.
The centipede is actually made up of a bunch of individual segments. Each segment moves horizon- tally across the screen, and a segment turns around and moves down a row of mushrooms toward the zapper whenever it runs into the edge of the screen or a mushroom. The segments all move at a fixed speed, but each segment keeps track of whether it is moving to the left or the right. At the start of the game, all of the segments are adjacent to each other and heading in the same direction. Thus, they appear to be a single centipede. As the game progresses, the segments may head in different directions and no longer appear as a single centipede.
The zapper moves left and right in response to the player pressing the left and right arrow keys. The zapper shoots a missile by hitting the space-bar. If a missile hits a mushroom, the mushroom disappears and the player earns one point. If a missile hits a centipede segment, the player earns 5 points. Also, the segment that was shot disappears and a mushroom appears in its place. The centipede moves its remaining segments, as before. If a segment in the middle of the "centipede" is hit, the segments between the new mushroom and the "tail" of the centipede will run into the newly created mushroom and turn around. Thus, the net effect is that there will now appear to be two "smaller centipedes" headed toward the zapper.
The game ends either when the zapper shoots all of the segments or when a segment runs into the zapper. In either case, a message is displayed to the user indicating that the game is over and showing the player's final score.
The game will include a black background, a score-keeping mechanism, a zapper, mushrooms, and all those centipede segments. We provide some suggestions on how to design and implement all of these pieces of the program below so read through all of this handout before starting anything!.
The starter folder includes six mushroom images and two segment images. You only need to use one of each. ("shroom2.gif" is our personal favorite.) Feel free to use the others if you want to add a little variety or animation to your program. Also, feel free to edit and include your own images, although it will be easiest if you stick to images that are 16x16 pixels.
The scorekeeper should display the score at the bottom of the screen. You must be able to increase the score when a missile hits a segment or a mushroom.
The zapper is an object that will appear at the bottom of the screen. It must provide methods for responding to the player's key strokes. Thus, a zapper should be able to move left, move right, and shoot a missile. If the zapper is hit by a centipede segment, it should stop being able to move or fire. If you want, you can make the zapper disappear in some interesting way.
The missiles shot by the zapper are active objects. They should move up the screen and stop when they reach the top, hit a mushroom, or hit a segment.
The centipede has a different representation than our Nibbles snake. In particular, a centipede is an active object that keeps a collection of segments inside it. Each segment can be thought of as a separate entity that has a VisibleImage associated with it and it will keep track of where it is and which direction it is moving. The segments are all initially placed next to each other and facing to the right, so that they appear to move as a single, long "centipede". The Centipede animates the segments by making each segment take a step. (The segments themselves are NOT active objects.) Think of this like our chain example. The segments are individual objects that are animated using a single active object, the centipede. A segment takes a step by moving a fixed distance in the direction that that segment is heading. The centipede moves all of the segments and then should pause only after all of the segments are moved. Do not use smooth scrolling or pause between moving individual segments. If you do, the centipede may not appear to move properly - it will stretch out or shrink, or individual segments may move out of alignment and not look quite right.
If a segment is about to step off the screen or hit a mushroom horizontally, it should move down the screen by one row of mushrooms. The segment should also change its direction so that it will move in the opposite direction the next time it is asked to take a step. Don't worry about the centipede running into segments when it moves down a row (this both makes the implementation more straightforward as well as keep the centipede from getting stuck). When a segment is hit by a missile, it should disappear from the screen.
You need to be careful about how you keep track of the segments in the centipede. We suggest you use an array of Segment objects. Most importantly, DO NOT TRY TO DELETE SEGMENTS THAT HAVE BEEN HIT FROM THE ARRAY AND SHIFT OTHER ELEMENTS IN THE ARRAY OVER TO FILL THE HOLE. If you do this, bad things may happen if a missile tries to rearrange your array to delete a segment that has been hit at the same time that the segment is being moved across the screen. Instead, when a segment is hit, just set a variable within the object representing the segment to indicate that it is dead and hide it from the screen.
As you can see from the demo, mushrooms never overlap and are placed inside the squares of a grid laid over the canvas. We suggest using a two dimensional array of VisibleImages to store the mushrooms. Make the array large enough to hold mushrooms laid out over the whole canvas. For reasons similar to those described above for segments, you should fill all entries in your array with mushroom visible images. Only show images for mushrooms that should be visible, and NEVER DELETE ELEMENTS FROM THE ARRAY OR SET ENTRIES TO NULL. Intuitively, if there is enough room for a grid of mushrooms with 15 rows and 10 columns in the canvas, you would create a 15x10 array and store a mushroom in each cell. The following shows how the screen would look if that grid were displayed while all but 7 mushrooms were hidden:
Your program will comprise several classes, corresponding to the objects just described.
The easiest way to provide information to the Missile is to have the Zapper's shoot method take the Field and Centipede as parameters, and then pass them to the Missile's constructor when that method creates the new missile.
(Alternatively, you could store the field and centipede in instance variables in the zapper, but this is a little tricky to set up because the centipede will also need to store the zapper so that its segments will be able to kill the zapper. This circularity between the zapper and the centipede can be resolved in a number of ways, but just passing the necessary information to shoot is the easiest.)
As indicated in the heading of this document, you will need to turn in a design plan for your Centipede program well before the program itself. You should include in your design a sketch of each class including the types and names of all instance variables you plan to use, and the headers of all methods you expect to write. You should write a brief description of the purpose/function of each instance variable and method.
In addition, you should provide internal comments for any method whose implementation is at all complicated. In particular, if a method is complicated enough that it will invoke other methods you write (rather than just invoking methods provided by Java or our library), then include comments for the method so that we will see how you expect to use your own methods.
From your design, we should be able to find the answers to questions like the following easily:
The more time you spend on the design, the easier it will be to complete the program.
The following constants appear in the starter code. Using them will ensure that your segments move at a reasonable speed and are able to turn correctly.
In the Field class:
// dimensions of the canvas private static final int CANVAS_WIDTH = 400; private static final int CANVAS_HEIGHT = 512; // size of mushroom pictures private static final int SHROOM_SIZE = 16; // dimensions of the mushroom array private static final int NUM_ROWS = CANVAS_HEIGHT / SHROOM_SIZE; private static final int NUM_COLS = CANVAS_WIDTH / SHROOM_SIZE;In the Segment class:
// width of segment image private static final int SEGMENT_WIDTH = 16; // number of pixels a segment should travel in the X direction private static final int SEGMENT_STEP_X = 4; // number of pixels a segment should move in the Y direction private static final int SEGMENT_STEP_Y = SEGMENT_WIDTH;In the Centipede class:
// offset between segments when first created. private static final int SEGMENT_OFFSET_X = 12; // pause time between moving all of the segments private static final int CENTIPEDE_PAUSE = 25;In the Missile class:
// Distance missile should move after each iteration private static final int DISTANCE_TO_MOVE = 16; private static final int PAUSETIME = 33;In the Zapper class:
// width of the zapper private static final int BODY_WIDTH = 16;
Feel free to adjust these constants as you wish. However, FIELD_WIDTH, SHROOM_SIZE, SEGMENT_OFFSET_X, and DISTANCE_TO_MOVE should always be multiples of SEGMENT_STEP_X. If they are not, your centipedes may appear to separate or bunch up after running into obstacles, because some segments will turn around when they are a pixel or two further away from the obstacle than others.
Begin copying the starter folder as usual. We strongly encourage you to proceed as suggested below to ensure that you can turn in a running program. While a partial program will not receive full credit, a program that does not run at all generally receives a lower grade. Moreover it is easier to debug a program if you know that some parts do run correctly.
public boolean shroomIsVisible(double x, double y)
You may implement this test in any reasonable way. You may find two helper methods that we have provided in Field for converting screen locations to array indices useful:
// Convert a y coordinate in pixels to the corresponding // row in the mushroom array private int getRow(double y) { return (int)(y / SHROOM_SIZE); } // Convert a x coordinate in pixels to the corresponding // column in the mushroom array private int getColumn(double x) { return (int)(x / SHROOM_SIZE); }For example, getColumn will convert the x coordinate 50 to the column index 3, and getRow will convert the y coordinate 100 to the row index 6. Thus, the mushroom image corresponding to the screen location (50,100) on the screen is stored in your 2D array at row 6 and column 3.
Note that these two methods may return rows and columns that are not within the bounds of the array if x and y are negative or larger than CANVAS WIDTH and CANVAS HEIGHT. So, be sure to check that the x and y coordinates passed into shroomIsVisible are within bounds before proceeding. If they are not, we can conclude that no mushroom is visible at that location.
There is a great deal of functionality to aim for in this test program. Do not worry if you cannot implement all of the functionality. Get as much of it working as you can. As we have done throughout the semester, we will consider both issues of correctness and issues of style when grading your program. It is always best to have full functionality, but you are better off having most of the functionality and a beautifully organized program than all of the functionality with a program that is sloppy, poorly commented, etc.
For each extra credit item that you do, list it in the comments at the top of the
CentipedeController class or you may not get credit for it!
Some possible extensions are:
Your design should be turned in on paper in class or e-mailed to the professor. Keep a copy for yourself since we won't return it to or give you feedback on it until after the program is due. When your work is complete you should deposit in the dropbox folder Before turning it in, please be sure that your folder contains all of the .java files, .class files, etc. as we can't give credit for anything we don't receive.
Before turning it in, make sure the folder name includes your name and the phrase "TP2". Also make sure to double check your work for correctness, organization and style.
This program is due at midnight on December 8th, the last day of classes. While you may turn your program in late, you will be assessed a 10 point penalty for each day it is late. I.e., if you turn it in by midnight on December 9th, you will receive a 10 point penalty. If you turn it in at midnight on December 10th, you will receive a 20 point penalty, etc.
Grading Point AllocationsValue | Feature |
Design preparation (20 pts total) | |
Syntax Style (14 pts total) | |
6 pts. | Descriptive and helpful comments |
2 pts. | Good names |
2 pts. | Good use of constants |
2 pts. | Appropriate formatting |
2 pts. | Appropriate use of public/private |
Code quality (26 pts total) | |
5 pts. | Conditionals and loops |
5 pts. | General design/Efficiency issues |
5 pts. | Parameters, variables, and scoping |
5 pts. | Appropriate use of arrays |
6 pts. | Misc. |
---- | Correctness (38 pts total) |
Basic setup (6 pts) | |
3 pts. | general setup (score keeper, etc.) |
3 pts. | random mushrooms |
Zapper (6 pts) | |
2 pts. | drawn correctly |
2 pts. | moves left, right |
3 pts. | shoots missiles |
Missiles (8 pts) | |
2 pts. | missile moves up |
2 pts. | missile stops at top |
2 pts. | missile can hit segments |
1 pts. | missile can hit mushrooms |
1 pts. | segments turn into mushrooms |
Segments and Centipede (12 points total) | |
3 pts. | segment moves right or left |
3 pts. | segment turns around at edges |
3 pts. | segment turns around at mushrooms |
3 pts. | segment moves down when it turns |
Ending the Game (6 points total) | |
1 pts. | Game ends when all segments are hit |
1 pts. | Game ends when zapper is hit |
4 pts. | Scorekeeper keeps score correctly |
2 pts. | Miscellaneous points (for EC) |
100 pts. | Total |
5 pts. | Extra credit |