CS 51 Test Program # 2
Centipede
Due: December 12th at 4:00 PM
(Design due: November 30th, in class)
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.
Our simplified game begins with a centipede at the top of a field of mushrooms. A bug "zapper" sits at the bottom of the screen. The zapper's job is to defend itself against the attacking centipede.
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.
You should begin the game by setting it up. This involves creating 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.
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 will keep track of 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.) A segment takes a step by moving a fixed distance in the direction that that segment is heading. The centipede 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, 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. 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.
You may also want to define other classes if you believe they will simplify your design.
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 pseudo-code 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 pseudo-code 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 static private final int CANVAS_WIDTH = 400; static private final int CANVAS_HEIGHT = 512; // size of mushroom pictures static private final int SHROOM_SIZE = 16; // dimensions of the mushroom array static private final int NUM_ROWS = CANVAS_HEIGHT / SHROOM_SIZE; static private final int NUM_COLS = CANVAS_WIDTH / SHROOM_SIZE;
In the Segment class:
// width of segment image static private final int SEGMENT_WIDTH = 16; // number of pixels a segment should travel in the X direction static private final int SEGMENT_STEP_X = 4; // number of pixels a segment should move in the Y direction static private final int SEGMENT_STEP_Y = SEGMENT_WIDTH;
In the Centipede class:
// offset between segments when first created. static private final int SEGMENT_OFFSET_X = 12; // pause time between moving all of the segments static private final int CENTIPEDE_PAUSE = 25;
In the Missile class:
// distance for missile to move each time interval. static private final int DISTANCE_TO_MOVE = 12;
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 by downloading the starter project from the handouts web page. 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.
Since we have deliberately left out many features of the original Centipede game, there are clearly many additional features you could add to your program. We will give 1-2 points for each extension, for a maximum of 6 points extra credit. Some possible extensions are:
Your design should be either neatly written or typed, and it should be turned in on paper at the beginning of class on Friday, November 30. We will NOT return the design to you before the program is due. Thus you should keep a copy of your design.
Submit your code in the usual way by exporting and dragging your project into the Dropoff folder for your section. Name your folder with your last name followed by TP2. Also, be sure to double check your work for correctness, organization and style.
This program is due at 4 p.m. on December 12th, 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 4 p.m. on December 6th, you will receive a 10 point penalty. If you turn it in at 4 p.m. on December 7th, you will receive a 20 point penalty, etc.
Grading Point AllocationsValue | Feature |
Design preparation (20 pts total) | |
2 pts | Variable and constant names and types |
2 pts | Method signatures |
2 pts | English descriptions |
2 pts | Pseudocode |
4 pts | Plausibility |
Grading Point AllocationsValue | Feature |
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 |
Semantic style (18 pts total) | |
4 pts. | Conditionals and loops |
4 pts. | Efficiency issues |
4 pts. | Parameters, variables, and scoping |
3 pts. | Appropriate selection of arrays or recursive data structures |
3 pts. | Correct use of arrays or recursive data structure |
Organization (14 pts total, 2 for each class) | |
Appropriate methods, parameters, instance variables and constants | |
Setup (12 pts total) | |
2 pts. | zapper drawn at bottom |
2 pts. | one segment drawn correctly |
2 pts. | whole centipede drawn correctly |
2 pts. | one mushroom drawn correctly |
2 pts. | random mushrooms drawn correctly |
2 pts. | initial score or message correct |
Zapper (8 points total) | |
3 pts. | zapper moves left, right |
3 pts. | zapper shoots missile |
2 pts. | zapper cannot move off screen |
Missiles (8 points total) | |
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 (10 points total) | |
2 pts. | segment moves right or left |
2 pts. | segment turns around at edges |
2 pts. | segment turns around at mushrooms |
2 pts. | segment moves down when it turns |
2 pts. | array of segments move correctly |
Ending the Game (4 points total) | |
1 pts. | Game ends when all segments are hit |
1 pts. | Game ends when zapper is hit |
2 pts. | Scorekeeper keeps score correctly |
051