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:
You can select the workspace from the screen which pops up. The attached image shows how it can be selected.
You can see the eclipse workbench on the screen. The attached screen shot shows the Eclipse project screen.
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.
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.
3. Download the Source Code
You can download the full source code of this example here: Java Snake Game Example
Please check this link for detailed implementation of this game in java console along with the unhandled cases.