CIT 590/591 Assignment 11: Snake
Fall 2012, David Matuszek

Purposes of this assignment

General idea of the assignment

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.

Player options

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_WVK_IVK_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_AVK_JVK_LEFT Turn 90 counterclockwise Begin moving left
s or k or ↓ VK_SVK_KVK_DOWN Ignore Begin moving down
d or l or → VK_DVK_LVK_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.");
                }
            }
        });
    }
}

Details

Moving the snake

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.

Drawing the snake

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.

Placing the flies

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.

Use MVC

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.

Scoring

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.

Structure of the assignment

You may have additional classes and methods as needed, and they should be documented and unit tested as appropriate.

Grading

It would be a good idea to read How Assignments Are Graded, but here's a summary: Do exactly what the assignment says to do, use good programming style, test your program carefully, zip up your program (if it's more than a single file), and turn it in via Blackboard. Late programs will lose points.

Due date

Your program is due before