Core Java

Java Snake Game Example

1. Introduction

In this post, we will develop and design a Snake Game with Eclipse using Java and Java Swing. Eclipse setup is also included in this article.

2. Java Snake Game Example

The snake game was created back in 1970. In 1980, a new version of the snake game evolved. In the 1990s, Nokia had this version of the snake game on its mobile phone. The game is related to moving a snakehead by using the arrows left, right, up, and down to eat an apple. When you eat the apple, the snake becomes one block bigger. If the snake hits the walls of the screen, the game is over. The score is dependent on the number of apples eaten. Below is the quote from the creator of the game on Nokia: Taneli Armanto

“I NEVER IMAGINED IT’D BECOME SO POPULAR. Maybe it was the massive distribution of the phone, the simplicity of the game or the ultimate combination of the two — but Snake became a phenomenon. People were starting to stare at their cell phones for extended amounts of time.”

Armanto – Creator of Snake game on Nokia

2.1 Prerequisites

Java 8 is required on the Linux, windows, or mac operating system. Eclipse Oxygen can be used for this example.

2.2 Download

You can download Java 8 from the Oracle website. Eclipse Oxygen can be downloaded from the Eclipse website.

2.3 Setup

2.3.1 Java Setup

You can set the environment variables for JAVA_HOME and PATH. They can be set as shown below:

Setup

JAVA_HOME="/desktop/jdk1.8.0_73"
export JAVA_HOME
PATH=$JAVA_HOME/bin:$PATH
export PATH

2.3.2 Eclipse Setup

The ‘eclipse-java-oxygen-2-macosx-cocoa-x86_64.tar’ can be downloaded. The tar file is opened by double click. The tar file is unzipped by using the archive utility. After the unzipping, you will find the eclipse icon in the folder. You can move the eclipse icon from the folder to applications by dragging the icon.

2.4 Running Eclipse

You can click on the eclipse icon to launch Eclipse. The eclipse screen pops up as shown in the screenshot below:

Java Snake - Running Eclipse
Running Eclipse

You can select the workspace from the screen which pops up. The attached image shows how it can be selected.

Java Snake - Eclipse Workspace
Eclipse Workspace

You can see the eclipse workbench on the screen. The attached screen shot shows the Eclipse project screen.

Java Snake - Eclipse IDE
Eclipse IDE

2.5 How to Design Snake Game in Java

The key classes in the Snake game are Snake, Board, Apple, Wall, and the Manager. The class SnakeGame is the game engine that runs the game. It has the latest location about the snake, apple and the board. Board has a matrix of cells. The board screen has a wall. The code snippet below shows the Board class. The Board has a set of cells with dots. Board’s width and height are set in the constructor. Snake and Apple objects can be set on the board on a cell using the method setObjectOnLocation. getObjectOnLocation is used to retrieve the current object in the cell location.

Board

package org.gaming;

public class Board {

	private int width, height;
	private char[][] boardMatrix;

	public Board(int width, int height) {
		this.width = width;
		this.height = height;
		this.boardMatrix = new char[this.height][this.width];
	}

	
	public void initBoard() {
		for (int i = 0; i < this.height; i++) {
			for (int j = 0; j < this.width; j++) {
				this.boardMatrix[i][j] = '.';
			}
		}
	}

	
	public void printBoard() {
		for (int i = 0; i < this.height; i++) {
			for (int j = 0; j < this.width; j++) {
				System.out.print(this.boardMatrix[i][j]);
			}
			System.out.println();
		}
	}

	
	public void ClearScreenLocation(int x, int y) {
		this.boardMatrix[y][x] = '.';
	}

	
	public int getBoardWidth() {
		return this.width;
	}

	public int getBoardHeight() {
		return this.height;
	}

	public char getObjectOnLocation(int x, int y) {
		return this.boardMatrix[y][x];
	}

	
	public void setObjectOnLocation(BoardComponent object, int x, int y) {
		this.boardMatrix[y][x] = object.getIcon();
	}
}

The code snippet below shows the BoardComponent class. BoardComponent has location coordinates x, y, and icon representing the component. Getters and setters are used to get and set the attributes of BoardComponent.

BoardComponent

package org.gaming;

public class BoardComponent {
	
	private int x, y;
	private char icon;
	

	public int getX() {
		return this.x;
	}

	public int getY() {
		return this.y;
	}

	public char getIcon() {
		return icon;
	}

	public void setX(int newLocation) {
		this.x = newLocation;
	}
	
	public void setY(int newLocation) {
		this.y = newLocation;
	}
	
	public void setIcon(char newSymbol) {
		this.icon = newSymbol;
	}
}

The code snippet below shows the AppleElement class. This class extends BoardComponent class. It has a constructor which takes the symbol has the parameter. It has a method addRandomApple method to set the apple on the board.

AppleElement

package org.gaming;

public class AppleElement extends BoardComponent {

	public AppleElement(char symbol) {
		setIcon(symbol);
	}

	public void addRandomApple(Board screen, AppleElement apple) {
		
		int x = (int) (((Math.random()) * (screen.getBoardWidth() - 1)));
		int y = (int) (((Math.random()) * (screen.getBoardHeight() - 1)));

		if(x==0)
		{
			x = 2;
		}
		
		if(y==0)
		{
			y= 2;
		}
		screen.setObjectOnLocation(apple,x,y);
				
	}
}

The code snippet below shows the RoomWall class. It is a subclass of BoardComponent class. It has constructors to set the default icon or a custom icon for the wall cells. To set the walls on north, south, west, and east, addRoomWallRow and addRoomWallColumn methods are in the RoomWall class.

RoomWall

package org.gaming;

public class RoomWall extends BoardComponent {

	public RoomWall() {
		setIcon('^');
	}

	public RoomWall(char icon) {
		setIcon(icon);
	}


	public void addRoomWallRow(Board board, RoomWall wall, int rowNumber) {
		for (int i = 0; i < board.getBoardWidth(); i++) {
			board.setObjectOnLocation(wall, i, rowNumber);
		}
	}

	public void addRoomWallColumn(Board board, RoomWall wall, int columnNumber) {
		for (int i = 0; i < board.getBoardHeight(); i++) {
			board.setObjectOnLocation(wall, columnNumber, i);
		}
	}
}

The code snippet below shows the SnakeElement class. SnakeElement is a subclass of BoardComponent. It has a constructor to set the symbol and location coordinates x and y.

SnakeElement

package org.gaming;

public class SnakeElement extends BoardComponent {

	public SnakeElement(char symbol, int xStartingLocation, int yStartingLocation) {
		setIcon(symbol);
		setX(xStartingLocation);
		setY(yStartingLocation);
	}
	
	public void moveLeft(Board screen, SnakeElement snake) {
		snake.setX(getX() - 1);
		screen.setObjectOnLocation(snake, snake.getX(), snake.getY());
		screen.ClearScreenLocation(snake.getX() + 1, snake.getY());
	}
	
	public void moveRight(Board screen, SnakeElement snake) {
		snake.setX(getX() + 1);
		screen.setObjectOnLocation(snake, snake.getX(), snake.getY());
		screen.ClearScreenLocation(snake.getX() - 1, snake.getY());
	}
	
	public void moveUp(Board screen, SnakeElement snake) {
		snake.setY(getY() - 1);
		screen.setObjectOnLocation(snake, snake.getX(), snake.getY());
		screen.ClearScreenLocation(snake.getX(), snake.getY() + 1);
	}
	
	public void moveDown(Board screen, SnakeElement snake) {
		snake.setY(getY() + 1);
		screen.setObjectOnLocation(snake, snake.getX(), snake.getY());
		screen.ClearScreenLocation(snake.getX(), snake.getY() - 1);
	}
}

The code snippet below shows the Manager class. The Manager class creates the Board and RoomWalls. The initial positions of the snake and the apple are set. The key events are captured to move the snake.

Manager

package org.gaming;

import java.util.Scanner;

public class Manager {

	public static void main(String[] args) {

		final int BOARD_WIDTH = 20; 
		final int BOARD_HEIGHT = 10; 
		final int START_X = BOARD_WIDTH / 2;
		final int START_Y = BOARD_HEIGHT / 2;


		Board board = new Board(BOARD_WIDTH, BOARD_HEIGHT);
		board.initBoard();

		RoomWall wall = new RoomWall('^');
		wall.addRoomWallRow(board, wall, 0); 
		wall.addRoomWallRow(board, wall, board.getBoardHeight() - 1); 
		wall.addRoomWallColumn(board, wall, 0); 
		wall.addRoomWallColumn(board, wall, board.getBoardWidth() - 1); 

		SnakeElement snake = new SnakeElement('~', START_X, START_Y);
		board.setObjectOnLocation(snake, snake.getX(), snake.getY());

		AppleElement apple = new AppleElement('&');
		apple.addRandomApple(board, apple);
		

		Scanner scanner = new Scanner(System.in);
		char input;


		boolean isRunning = true;

		while (isRunning) {
			board.printBoard();
			switch (input = scanner.nextLine().charAt(0)) {
			case 'l':
				snake.moveLeft(board, snake);
				break;
			case 'r':
				snake.moveRight(board, snake);
				break;
			case 'u':
				snake.moveUp(board, snake);
				break;
			case 'd':
				snake.moveDown(board, snake);
				break;
			}
		}
	}

}

The snapshot below is the output printed when the Manager class is run as the java application in eclipse.

Java Snake
Snake Game

This is a basic version of the game but not complete. Let us look at the swing version which evolves this version to next level in the next section.

2.6 Design Snake Game in Java Swing

To design the snake game, let us start with a swing JFrame class SnakeGame. The code snippet below shows the SnakeGame class. This class has a default constructor which initialises the Screen. The initScreen method creates a new ScreenPanel. The SnakeGame JFrame is created and it is setVisible.

Snake Game

package org.gaming;

import java.awt.EventQueue;
import javax.swing.JFrame;

public class SnakeGame extends JFrame {

    public SnakeGame() {
        
        initScreen();
    }
    
    private void initScreen() {
        
        add(new ScreenPanel());
               
        setResizable(false);
        pack();
        
        setTitle("Snake");
        setLocationRelativeTo(null);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    }
    

    public static void main(String[] args) {
        
        EventQueue.invokeLater(() -> {
            JFrame frame = new SnakeGame();
            frame.setVisible(true);
        });
    }
}

The code snippet below shows the ScreenPanel class. ScreenPanel class extends JPanel and implements the ActionListener to listen to screen events. It has a default constructor which initializes the screen panel. The initScreenPanel method loads the icons and starts the snake game by creating an apple and the snake parts. The action events on the screen move the snake based on the current location of the snake and apple. If the collision happens, the number of snake parts increase. If the snake hits the walls, the game is over.

Screen Panel

package org.gaming;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import javax.swing.ImageIcon;
import javax.swing.JPanel;
import javax.swing.Timer;

public class ScreenPanel extends JPanel implements ActionListener {

    private final int SCREEN_WIDTH = 300;
    private final int SCREEN_HEIGHT = 300;
    private final int DOT_ICON_SIZE = 10;
    private final int DOT_ICONS = 900;
    private final int RAND_POS = 29;
    private final int DELAY = 140;

    private final int x[] = new int[DOT_ICONS];
    private final int y[] = new int[DOT_ICONS];

    private int parts;
    private int apple_x;
    private int apple_y;

    private boolean leftDirection = false;
    private boolean rightDirection = true;
    private boolean upDirection = false;
    private boolean downDirection = false;
    private boolean inSnakeGame = true;

    private Timer timer;
    private Image snakepart;
    private Image apple;
    private Image snakehead;

    public ScreenPanel() {
        
        initScreenPanel();
    }
    
    private void initScreenPanel() {

        addKeyListener(new GameKeyAdapter());
        setBackground(Color.black);
        setFocusable(true);

        setPreferredSize(new Dimension(SCREEN_WIDTH, SCREEN_HEIGHT));
        loadIcons();
        initSnakeGame();
    }

    private void loadIcons() {

        ImageIcon iisnakepart = new ImageIcon("src/resources/snakepart.png");
        snakepart = iisnakepart.getImage();

        ImageIcon iiapple = new ImageIcon("src/resources/apple.png");
        apple = iiapple.getImage();

        ImageIcon iisnakehead = new ImageIcon("src/resources/snakehead.png");
        snakehead = iisnakehead.getImage();
    }

    private void initSnakeGame() {

        parts = 5;

        for (int z = 0; z < parts; z++) {
            x[z] = 50 - z * 10;
            y[z] = 50;
        }
        
        locateApple();

        timer = new Timer(DELAY, this);
        timer.start();
    }

    @Override
    public void paintComponent(Graphics g) {
        super.paintComponent(g);

        doDrawing(g);
    }
    
    private void doDrawing(Graphics g) {
        
        if (inSnakeGame) {

            g.drawImage(apple, apple_x, apple_y, this);

            for (int z = 0; z  0; z--) {
            x[z] = x[(z - 1)];
            y[z] = y[(z - 1)];
        }

        if (leftDirection) {
            x[0] -= DOT_ICON_SIZE;
        }

        if (rightDirection) {
            x[0] += DOT_ICON_SIZE;
        }

        if (upDirection) {
            y[0] -= DOT_ICON_SIZE;
        }

        if (downDirection) {
            y[0] += DOT_ICON_SIZE;
        }
    }

    private void findCollision() {

        for (int z = parts; z > 0; z--) {

            if ((z > 6) && (x[0] == x[z]) && (y[0] == y[z])) {
                inSnakeGame = false;
            }
        }

        if (y[0] >= SCREEN_HEIGHT) {
            inSnakeGame = false;
        }

        if (y[0] = SCREEN_WIDTH) {
            inSnakeGame = false;
        }

        if (x[0] < 0) {
            inSnakeGame = false;
        }
        
        if (!inSnakeGame) {
            timer.stop();
        }
    }

    private void locateApple() {

        int r = (int) (Math.random() * RAND_POS);
        apple_x = ((r * DOT_ICON_SIZE));

        r = (int) (Math.random() * RAND_POS);
        apple_y = ((r * DOT_ICON_SIZE));
    }

    @Override
    public void actionPerformed(ActionEvent event) {

        if (inSnakeGame) {

            findAppleIcon();
            findCollision();
            shift();
        }

        repaint();
    }

    private class GameKeyAdapter extends KeyAdapter {

        @Override
        public void keyPressed(KeyEvent event) {

            int key = event.getKeyCode();

            if ((key == KeyEvent.VK_LEFT) && (!rightDirection)) {
                leftDirection = true;
                upDirection = false;
                downDirection = false;
            }

            if ((key == KeyEvent.VK_RIGHT) && (!leftDirection)) {
                rightDirection = true;
                upDirection = false;
                downDirection = false;
            }

            if ((key == KeyEvent.VK_UP) && (!downDirection)) {
                upDirection = true;
                rightDirection = false;
                leftDirection = false;
            }

            if ((key == KeyEvent.VK_DOWN) && (!upDirection)) {
                downDirection = true;
                rightDirection = false;
                leftDirection = false;
            }
        }
    }
}

The snapshot below is the JFrame window that pops up when the SnakeGame Class is run as the java application in eclipse.

Snake Swing Game

3. Download the Source Code

Download
You can download the full source code of this example here: Java Snake Game Example

Bhagvan Kommadi

Bhagvan Kommadi is the Founder of Architect Corner & has around 20 years’ experience in the industry, ranging from large scale enterprise development to helping incubate software product start-ups. He has done Masters in Industrial Systems Engineering at Georgia Institute of Technology (1997) and Bachelors in Aerospace Engineering from Indian Institute of Technology, Madras (1993). He is member of IFX forum,Oracle JCP and participant in Java Community Process. He founded Quantica Computacao, the first quantum computing startup in India. Markets and Markets have positioned Quantica Computacao in ‘Emerging Companies’ section of Quantum Computing quadrants. Bhagvan has engineered and developed simulators and tools in the area of quantum technology using IBM Q, Microsoft Q# and Google QScript. He has reviewed the Manning book titled : "Machine Learning with TensorFlow”. He is also the author of Packt Publishing book - "Hands-On Data Structures and Algorithms with Go".He is member of IFX forum,Oracle JCP and participant in Java Community Process. He is member of the MIT Technology Review Global Panel.
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

1 Comment
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Abhishek Sarkar
2 years ago

Please check this link for detailed implementation of this game in java console along with the unhandled cases.

Last edited 2 years ago by Abhishek Sarkar
Back to top button