Snake is a classic computer game, with many variations. In this assignment you will implement a relatively simple one-person version.
In this game the display area is divided into a large number of cells. Each cell is cellSize × cellSize pixels. You will control a "snake" that is one cell wide and starts out initialLength cells long. The snake moves at a constant speed of speed cells per second; you can control only the direction that the snake is moving.
During the game, "flies" (black cells) randomly appear, stay for a random amount of time, and (if not eaten by the snake) disappear again. The object of the game is to move the snake to capture the flies by running into them before they disappear. Each time a fly is eaten, the snake increases in length by lengthIncrement cells. There may be between one and maxFlies visible at any time.
The game continues until the snake runs into the edge of the playing area, or runs into itself. The score is the number of flies eaten before this occurs.
Give the player the following options:
When the game ends, display the player's score (the number of flies eaten). Give the player the opportunity to quit, or to play another game, with the same or different options.
| Key typed | KeyEvent | Relative move | Absolute move | Where to get key code |
|---|---|---|---|---|
| w or i or ↑ | VK_W, VK_I, VK_UP |
Ignore | Begin moving up | When a key is pressed, a KeyEvent occurs. You can capture this event with a KeyListener or KeyAdapter and override its public void keyPressed(KeyEvent e) method. Then use the event's getKeyCode() method to get the (integer) key code. |
| a or j or ← | VK_A, VK_J, VK_LEFT |
Turn 90 counterclockwise | Begin moving left | |
| s or k or ↓ | VK_S, VK_K, VK_DOWN |
Ignore | Begin moving down | |
| d or l or → | VK_D, VK_L, VK_RIGHT |
Turn 90 clockwise | Begin moving right |
Handling keypresses is a little tricky. Here's some sample code to get you started.
import java.awt.event.KeyEvent;
import java.awt.event.KeyAdapter;
public class ArrowKeyTests extends JFrame {
public static void main(String[] args) {
new ArrowKeyTests().run();
}
private void run() {
JPanel panel = new JPanel();
add(panel);
pack();
setSize(100, 100);
setVisible(true);
setDefaultCloseOperation(EXIT_ON_CLOSE);
addKeyListener(new KeyAdapter() { // adds to this JFrame
@Override
public void keyPressed(KeyEvent e) {
if(e.getKeyCode() == KeyEvent.VK_UP) {
System.out.println("Up arrow pressed.");
}
if(e.getKeyCode() == KeyEvent.VK_DOWN) {
System.out.println("Down arrow pressed.");
}
if(e.getKeyCode() == KeyEvent.VK_LEFT) {
System.out.println("Left arrow pressed.");
}
if(e.getKeyCode() == KeyEvent.VK_RIGHT) {
System.out.println("Right arrow pressed.");
}
}
});
}
}
Use a frame rate of 24 frames/second. This allows you to have a reasonably smooth animation.
At the beginning of the game, the snake begins in the bottom center of the screen, moving upwards.
If the snake is moving at, for example, 3 cells/second, then you need to advance the snake by one cell every 8 frames (24/3 = 8), and similarly for other speeds.
You need to keep a list of all the "cells" occupied by the snake.
lengthIncrement cells. To do this, continue adding cells to the front of the snake as usual, so that the speed of the snake's head does not change, but stop removing cells from the end of the snake until its length has increased by the desired amount.Draw the snake by drawing a filled rectangle in each cell that the snake occupies.
Once everything is working, you can improve the appearance of the snake. Don't do it before that, because it's easy to get involved in improving the graphics, and that can be time consuming.
A simple improvement is to give the snake "eyes"--two dots in the head cell. The placement of these dots should depend on the direction that the snake is moving.
Another simple improvement would be to draw the snake's head with a filled circle, overlapping with a rectangle that fills the rear half of the cell.
I'm sure you can think of other improvements.
Flies should appear in random unoccupied cells. Do not place a fly in a cell containing another fly or part of the snake.
Each fly should stay where it is for a random amount of time, between some maximum and minimum. The minimum should be large enough that the snake has a reasonable chance to catch most of the flies. The maximum should be small enough so that the snake cannot catch them all.
There should always be at least one fly on the board.
The Model keeps track of all the information about the game state--where the flies are, where the snake is, how many flies have been caught, etc. The model also contains the Timer, which advances the state of the game 24 times a second. The model does not do any I/O, but it is an Observable, and as such it will notify observers whenever something has occured that should be displayed.
The GUI acts as the Controller. It allows the player to choose options (game size, etc.), and it accepts arrow key presses and tells the model about them. The GUI is not the View, but it does provide a space on the screen for the View.
The View is a JPanel, and it implements Observer. The task of the View is to draw everything that is happening in the Model. You will find it easiest, and almost certainly fast enough, to redraw everything whenever something changes.
The current score should be visible at all times, and the final score should be displayed in a dialog box or window when the game ends.
The score should increase each time the snake catches a fly; details are up to you. You could just decide score = number of flies eaten. However, something more creative, such as score = square of the length of the snake, will give more impressive scores, and probably make the game more interesting.
Provide some animation in the scoring window as well; for example, a snake circling it or wandering about randomly inside it. If one team member has done most of the work with the main animation, the other team member should do this animation.
SnakesnakeSnake (the controller), SnakeModel, SnakeView. SnakeModel.Snake_yourName_partnersNameYou may have additional classes and methods as needed, and they should be documented and unit tested as appropriate.