Introduction
The Snake game is a classic arcade game where the player controls a snake that grows longer as it eats food. The objective is to avoid colliding with the walls or the snake’s own body while collecting food items. In this tutorial, we will guide you step-by-step to create a simple version of the Snake game using the Java programming language.
Objective
The goal of this program is to help you understand how to create a basic Snake game using Java. We will cover the essentials like handling user input, creating game loops, collision detection, and basic rendering to the screen. By the end of this tutorial, you’ll have a fully functional Snake game written in Java.
Java Code for Snake Game
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 SnakeGame extends JPanel implements ActionListener { private final int TILE_SIZE = 30; private final int WIDTH = 800; private final int HEIGHT = 600; private final int ALL_TILES = (WIDTH * HEIGHT) / (TILE_SIZE * TILE_SIZE); private final int RAND_POS = 29; private final int DELAY = 140; private final int[] x = new int[ALL_TILES]; private final int[] y = new int[ALL_TILES]; private int snakeLength; private int foodX; private int foodY; private int direction = KeyEvent.VK_RIGHT; private boolean running = false; private boolean paused = false; private Timer timer; private Image body; private Image head; private Image food; public SnakeGame() { initBoard(); } private void initBoard() { addKeyListener(new TAdapter()); setBackground(Color.black); setFocusable(true); setPreferredSize(new Dimension(WIDTH, HEIGHT)); loadImages(); resetGame(); } private void loadImages() { ImageIcon iid = new ImageIcon("src/resources/dot.png"); body = iid.getImage(); ImageIcon iih = new ImageIcon("src/resources/head.png"); head = iih.getImage(); ImageIcon iif = new ImageIcon("src/resources/food.png"); food = iif.getImage(); } private void resetGame() { snakeLength = 3; for (int z = 0; z < snakeLength; z++) { x[z] = 50 - z * TILE_SIZE; y[z] = 50; } spawnFood(); running = true; timer = new Timer(DELAY, this); timer.start(); } private void spawnFood() { foodX = (int) (Math.random() * RAND_POS) * TILE_SIZE; foodY = (int) (Math.random() * RAND_POS) * TILE_SIZE; } @Override public void paintComponent(Graphics g) { super.paintComponent(g); doDrawing(g); } private void doDrawing(Graphics g) { if (running) { g.drawImage(food, foodX, foodY, this); for (int z = 0; z < snakeLength; z++) { if (z == 0) { g.drawImage(head, x[z], y[z], this); } else { g.drawImage(body, x[z], y[z], this); } } Toolkit.getDefaultToolkit().sync(); } else { gameOver(g); } } private void gameOver(Graphics g) { String msg = "Game Over!"; Font small = new Font("Helvetica", Font.BOLD, 30); FontMetrics metr = getFontMetrics(small); g.setColor(Color.white); g.setFont(small); g.drawString(msg, (WIDTH - metr.stringWidth(msg)) / 2, HEIGHT / 2); } private void move() { for (int z = snakeLength; z > 0; z--) { x[z] = x[(z - 1)]; y[z] = y[(z - 1)]; } switch (direction) { case KeyEvent.VK_LEFT: x[0] -= TILE_SIZE; break; case KeyEvent.VK_RIGHT: x[0] += TILE_SIZE; break; case KeyEvent.VK_UP: y[0] -= TILE_SIZE; break; case KeyEvent.VK_DOWN: y[0] += TILE_SIZE; break; } } private void checkCollisions() { if (x[0] < 0 || x[0] >= WIDTH || y[0] < 0 || y[0] >= HEIGHT) { running = false; } for (int z = snakeLength; z > 0; z--) { if (z > 3 && x[0] == x[z] && y[0] == y[z]) { running = false; } } } private void checkFood() { if (x[0] == foodX && y[0] == foodY) { snakeLength++; spawnFood(); } } @Override public void actionPerformed(ActionEvent e) { if (running) { move(); checkCollisions(); checkFood(); repaint(); } } private class TAdapter extends KeyAdapter { @Override public void keyPressed(KeyEvent e) { int key = e.getKeyCode(); if (key == KeyEvent.VK_PAUSE) { paused = !paused; } if (!paused) { if ((key == KeyEvent.VK_LEFT) && (direction != KeyEvent.VK_RIGHT)) { direction = KeyEvent.VK_LEFT; } if ((key == KeyEvent.VK_RIGHT) && (direction != KeyEvent.VK_LEFT)) { direction = KeyEvent.VK_RIGHT; } if ((key == KeyEvent.VK_UP) && (direction != KeyEvent.VK_DOWN)) { direction = KeyEvent.VK_UP; } if ((key == KeyEvent.VK_DOWN) && (direction != KeyEvent.VK_UP)) { direction = KeyEvent.VK_DOWN; } } } } } public class GameFrame extends JFrame { public GameFrame() { add(new SnakeGame()); setTitle("Snake Game"); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); pack(); setLocationRelativeTo(null); setVisible(true); } public static void main(String[] args) { SwingUtilities.invokeLater(() -> { new GameFrame(); }); } }
Explanation of the Program
The program is structured into several parts:
- Game Initialization: The
initBoard
method initializes the game screen, loads images, and starts the game timer. - Game Mechanics: The
move
method moves the snake, and thecheckCollisions
method handles collision detection with walls and the snake’s own body. - Game Loop: The
actionPerformed
method runs periodically and updates the game state, checking for collisions and food consumption. - Rendering: The
paintComponent
method is responsible for drawing the game components like the snake, food, and game-over message.
How to Run the Program
- Make sure you have Java Development Kit (JDK) installed on your system.
- Save the code into a file named
SnakeGame.java
. - Open the terminal or command prompt and navigate to the directory where the file is located.
- Compile the program by running
javac SnakeGame.java
. - Run the program using
java SnakeGame
.