$29
Notes:
• Name your sketch using your name and the assignment number, exactly as in this example:
LastnameFirstnameA5.
• There is only one question in this assignment, but it is broken into 7 phases (0 to 6). Hand in a working program for the last phase you were able to complete. For example, if you finish Phase 4, but Phase 5 is not working, do not hand in Phase 5. If it doesn't work you may not get all of the marks for Phases 1-4.
• Hand in one pde file only. Do not hand in any other types of files.
• Your mark will largely depend on how many phases you were able to complete.
• Please indicate clearly in the comments the highest phase you were able to complete.
• Assignments must follow the programming standards document published on the course website on UMLearn.
• After the due date and time assignments may be submitted but will lose 2% of marks per hour late or portion thereof.
• You may submit the assignment multiple times, but only the most recent version will be marked.
• These assignments are your chance to learn the material for the exams. Code your assignments independently. We use software to compare all submitted assignments to each other, and pursue academic dishonestly vigorously.
Q1: The Snake Game
Background:
There have been many “snake” games with a similar concept (https://en.wikipedia.org/wiki/Snake_(video_game_genre)). In this assignment you will create a simple game of this type.
There is a “snake” (a simple line of green circles) which moves around the canvas, controlled by the keyboard. The J and A keys will make the snake turn left, and D and L will make it turn right. Since you control how it turns, not the direction it moves, this makes it tricky at first. It does not move smoothly. Instead, every few frames, a new circle is added to the “head” end, and the circle at the “tail” end disappears. There are some “apples” (red circles). When the snake “eats” an apple, the snake grows. It doesn’t grow instantly,
but the circle at the tail will not disappear the next few times that the head moves. The snake cannot go off the canvas, or “bite itself”, or the game is over. If the snake eats all of the apples, then a new level begins, where the snake is longer, moves faster, grows faster, and has more apples to eat.
It is strongly recommended that you run the SampleSnakeGame that is posted on the COMP 1010 website, to see how the game is supposed to work. This is a Windows 64 application that will run in all of the campus computer labs, or on your own computer if it is a Windows 64 system with Java installed.
It is also strongly recommended that you complete each phase of the assignment before writing any code for the next phase.
1
ASSIGNMENT 5: The Snake Game
DEPARTMENT AND COURSE NUMBER: COMP 1010
Phase 0: Basic Functions
The canvas is treated as a grid of squares. There will be predefined constants ROWS and COLS giving the number of rows and columns in this grid, and a constant SQ_SIZE giving the size of each square (in pixels). These values are predefined for you in the supplied file TestA5Phase0. Note: The size command in the setup function must always use a canvas size of COLS*SQ_SIZE, ROWS*SQ_SIZE so that the game will exactly fit in the canvas. (But you have to do the calculation manually since Processing will not allow expressions in the size command.) The position of a circle will not be given in pixels. It will always be a position in the grid, using an x value from 0 to COLS-1, and a y value from 0 to ROWS-1, with 0 at the top or left, as usual.
The only things that have to be drawn in this assignment are sets of circles in the grid. The same function will be used to draw the snake, and also the apples. Define a function void drawCircles(int[] x, int[] y, int n, int colour) which will draw n circles in the canvas, at
the positions (x[i], y[i]) specified by the first n elements of the x and y arrays, and with the specified colour. The x and y values are in grid coordinates, not pixels.
To fill arrays with data, define a function void fillArray(int[] a, int n, int start, int delta) which will fill the first n elements of the array a with data. The first element should be set to start, and each element after that should differ from the previous one by delta. For example, fillArray(a,5,6,1) should set the first 5 elements of a to 6,7,8,9,10 (start at 6 and go up by 1), and fillArray(a,4,2,-1) should set the first 4 elements of a to 2,1,0,-1 (start at 2 and go down by 1).
To test your two functions, put them into the supplied file TestA5Phase0, and run that file. You do not need to write anything else. The program should produce the image shown above. You can get a few hints for future phases by looking at the supplied code.
Phase 1: Simple Snake
Start a new program. Define ROWS, COLS, and SQ_SIZE, and use the correct values in the size command, as in Phase 0. Add your drawCircles and fillArray functions from Phase 0.
Use global partially-full arrays to store the (x,y) coordinates of all of the circles that form the snake (as grid coordinates, not pixels). This includes a variable to control the current length of the snake. Make the arrays big enough to store a snake that fills the entire canvas (which will never happen, but it will give you plenty of room). Define a variable startingLength=5
which will control the length of the snake at the start of each level. This is not the same as the current length of the snake, which will change every time an apple is eaten (when you reach Phase 4). It is a variable, not a constant, because higher levels will start with longer snakes (when you reach Phase 6). But for Phase 1, a fixed value of 5 is OK.
Define a function void resetSnake() which will set the current length of the snake to the startingLength, and create a snake of that length with its head in the centre of the top row, and going straight up from there. (All of the circles except the head will be above the top of the canvas at first, with negative y coordinates.) Use your fillArray function to create the snake.
2
ASSIGNMENT 5: The Snake Game
DEPARTMENT AND COURSE NUMBER: COMP 1010
Define a function void moveSnake(int addX, int addY) which will move the snake by creating a new head right next to the old head, by adding the indicated numbers to the x and y coordinates. (So moveSnake(1,0) will move it right, moveSnake(0,-1) will move it up, etc.) The coordinates of the head of the snake should always be stored at index [0] of your arrays. The old head, and the other parts of the snake, should shift over one place in the array, except for the tail, which should disappear. The length of the snake should not change.
Create appropriate setup and draw functions. Define a variable snakeSpeed to control the speed with which the snake moves. Every snakeSpeed frames, you should move the snake. Try a value of 30, which will make the snake move once every half second. Do not change the frame rate! For test purposes in this phase, always move it downward. You should see a snake, 5 circles long, that starts at the top of the canvas, in the middle, with only its head showing at first, and which moves slowly down the canvas, until it disappears off the bottom.
Choose your own custom colours for the background, and the snake.
Phase 2: Snake Control
Now use the keyboard to control the motion of the snake. Use the special keyPressed() function. When the user presses the L or D key the snake should turn clockwise, and when the user presses the A or J key the snake should turn counter-clockwise. Accept upper or lower case letters. The keys do not directly control the snake’s direction. They control how the snake turns. That makes the game more fun (or more annoying, depending on your point of view).
Use a simple int variable to keep track of the snake’s current direction (down, left, up, or right, using the values 0 to 3 only). The easiest way to translate this direction into the x and y values needed by the moveSnake function is to use two constant arrays:
final int[] X_DIRECTIONS = {0,-1,0,+1}; //X change for down, left, up, right final int[] Y_DIRECTIONS = {+1,0,-1,0}; //Y change for down, left, up, right
Note that the four directions are in clockwise order.
Phase 3: Add Apples
Add another pair of partially-full arrays to store the position of all of the apples, including a variable that keeps track of the current number of apples (which will change, starting in Phase 4). Define a variable startingApples=5 which controls how many apples should appear at the start of each level. This works exactly the same way that startingLength does, but for apples, not the snake.
Unlike the snake, the apples appear at random locations. Define a
function int[] randomArray(int n, int max) which will create and
return an array of exactly n int values, randomly chosen from the values
0 to max. For example, randomArray(5,3) might return the array
{0,3,1,3,2}. Define a function resetApples() which will use randomArray to pick a random set of startingApples apples. Use drawCircles to draw the apples. Pick your own colour for the apples, but a shade of red would be traditional.
Make your program to create a set of 5 apples on the canvas, and draw them. (But they won’t do anything yet.)
3
ASSIGNMENT 5: The Snake Game
DEPARTMENT AND COURSE NUMBER: COMP 1010
Phase 4: Eat Apples
Add code to your program so that whenever the head of the snake hits an apple, the apple disappears, and the snake grows.
Define a function int searchArrays(int[] x,int[] y, int n, int start, int keyX, int keyY)
which will try to find a pair of coordinates (x[i],y[i]) in the first n elements of the arrays x and y that are equal to (keyX, keyY). But start the search at index start, not at index 0. (This is not important in this phase, but this same function will be used again in Phase 5.) If a matching coordinate is found, return the index i where it was found. If none is found, return -1.
Define a function void deleteApple(int eatenApple) which will delete the apple at the given index (eatenApple is the index) from the list of apples, reducing the number of apples by 1.
Use these two functions whenever the snake moves, to see if the head of the snake hit an apple, and to remove the apple if it did.
Use a global variable snakeGrowthRate to define how fast the snake grows. This is the number of extra circles to add to the snake whenever an apple is eaten. Try a value of 3 at first. It should be a variable, not a constant, since in Phase 6 it will start to increase.
To make the snake grow, you should modify the moveSnake function so that the circle at the tail does not disappear every time the snake moves. This will make the snake grow by one circle, or not. The snake must not grow to its full size instantly. It must grow one circle at a time, when it moves. Use a suitable global variable of some kind to keep track of whether the snake should grow or not, and by how much.
Phase 5: Detect Crashes
When the snake leaves the canvas, or the head of the snake hits any other part of the snake (biting itself), then the game should end, and a “Game Over” message should be displayed.
Define a function boolean detectCrash() which will return true if either of these things has happened, and the game should end. It must use the searchArrays function from Phase 4 to detect when the snake bites itself.
You can re-use the void showGameOverMessage() function from Assignment 2 to display the message when the game ends, or write a new one.
When the game is over, the game should freeze. The snake should stop moving and nothing else should happen. The user must close the canvas and restart the program to play again.
Phase 6: Add Levels
Add code so that when the last apple is eaten, a new level begins. Define a void newLevel() function that starts a new level. The snake should go back to the top centre of the canvas, with only its head showing, moving down. A new set of apples should appear. The snake should move faster, start longer, and grow faster when it eats apples. There should be more apples. Experiment with your own set of values for these things. The game should get more difficult, so that it becomes impossible before level 10 is reached, but the first few levels should not be too difficult.
4