If you’ve ever tried your hand at coding, chances are you’ve thought about creating a game. A Snake Game is a classic, combining simplicity with interactive gameplay.
In this article, I’ll walk you through building a Snake Game in Java, tailored to run directly on the command line.
We’ll explore key concepts like grid initialization, snake movement, food placement, and collision detection. By the end, you’ll have a working game that you can tweak and improve.
Table of Contents
1. Game Requirements
Before diving into the code, let’s outline the core requirements:
- Grid Initialization: Set up a fixed-dimension grid for gameplay.
- Snake Movement: Use keyboard inputs to control the snake.
- Food Placement: Randomly place food on the grid. Eating food extends the snake’s length.
- Collision Detection: End the game when the snake collides with itself or the grid boundaries.
- Advanced Features: Include optional elements like score tracking or obstacles.
2. Solution Overview
The game will use the following Java components:
- A 2D array to represent the game grid.
- A queue to track the snake’s body positions (FIFO).
- Input handling to read movement directions.
- Basic game logic to handle food placement, movement, and collisions.
3. Implementation
Below is the complete Java code for the Snake Game.
// Importing necessary libraries
import java.util.*;
// Entry point of the program
public class Main {
public static void main(String[] args) {
// Creates a new instance of the SnakeGame class and starts the game
SnakeGame snakeGame = new SnakeGame(6, 6);
snakeGame.start();
}
}
// Class to handle all game mechanics
class SnakeGame {
// A 2D array representing the game board
private final char[][] board;
// Queue to track the snake's body positions
private final Queue<Node> snakeBody = new LinkedList<>();
// Queue to store predefined or randomly generated food positions
private final Queue<Node> foodQueue = new LinkedList<>();
private final Random random = new Random(); // Random generator for food placement
private int currentRow = 0; // Snake head's current row position
private int currentCol = 0; // Snake head's current column position
private char currentHead = '>'; // Default head direction ('>' for right)
// Constructor initializes the board, snake's starting position, and food
public SnakeGame(int rows, int cols) {
board = new char[rows][cols]; // Create the game board with given dimensions
snakeBody.add(new Node(0, 0)); // Add the initial snake position to the queue
board[0][0] = currentHead; // Mark the snake's starting position on the board
generateFoodPositions(); // Generate predefined food positions
placeFood(); // Place the first food on the board
}
// Method to start the game loop
public void start() {
Scanner scanner = new Scanner(System.in); // Scanner to take user input
printBoard(); // Display the initial game board
// Game loop to keep running until the snake dies
while (true) {
System.out.print("Enter move (U, D, L, R): ");
// Take user input for movement and normalize it to uppercase
char move = scanner.next().toUpperCase().charAt(0);
// Process the move and update the game state
if (makeMove(move)) {
printBoard(); // Print the updated board if the move is valid
} else {
System.out.println("Game Over!"); // End the game if the move is invalid
break;
}
}
scanner.close(); // Close the scanner to release resources
}
// Method to process the player's move
private boolean makeMove(char direction) {
int newRow = currentRow, newCol = currentCol; // Variables to store the new position
char newHead; // Variable to store the new head direction
// Update the snake's head position and direction based on user input
switch (direction) {
case 'U': newRow--; newHead = '^'; break; // Move up
case 'D': newRow++; newHead = 'v'; break; // Move down
case 'L': newCol--; newHead = '<'; break; // Move left
case 'R': newCol++; newHead = '>'; break; // Move right
default:
System.out.println("Invalid move! Use U, D, L, R."); // Handle invalid input
return true; // Continue the game
}
// Check if the new move is valid
if (!isValidMove(newRow, newCol)) {
return false; // End the game if the move is invalid
}
// Check if the snake eats food
if (board[newRow][newCol] == 'X') {
placeFood(); // Place a new food item
} else {
// Remove the tail of the snake to maintain its length
Node tail = snakeBody.poll();
board[tail.row][tail.col] = '\0'; // Clear the tail position on the board
}
// Update the previous head position to the body symbol
board[currentRow][currentCol] = '.';
// Update the snake's head position
snakeBody.add(new Node(newRow, newCol)); // Add the new head position to the queue
currentRow = newRow; // Update the current row
currentCol = newCol; // Update the current column
currentHead = newHead; // Update the current head direction
board[newRow][newCol] = currentHead; // Mark the new head position on the board
return true; // Continue the game
}
// Method to check if a move is valid
private boolean isValidMove(int row, int col) {
// Ensure the new position is within the board and not colliding with the snake's body
return row >= 0 && row < board.length && col >= 0 && col < board[0].length && board[row][col] != '.';
}
// Method to generate predefined food positions
private void generateFoodPositions() {
foodQueue.add(new Node(1, 0)); // Food 1
foodQueue.add(new Node(2, 2)); // Food 2
foodQueue.add(new Node(3, 4)); // Food 3
foodQueue.add(new Node(5, 2)); // Food 4
foodQueue.add(new Node(4, 5)); // Food 5
}
// Method to place food on the board
private void placeFood() {
Node food;
if (!foodQueue.isEmpty()) {
food = foodQueue.poll(); // Place predefined food if available
} else {
do {
// Generate random food positions until an empty cell is found
food = new Node(random.nextInt(board.length), random.nextInt(board[0].length));
} while (board[food.row][food.col] != '\0');
}
board[food.row][food.col] = 'X'; // Mark the food position on the board
}
// Method to print the game board
private void printBoard() {
for (char[] row : board) {
for (char cell : row) {
System.out.print((cell == '\0' ? '■' : cell) + " "); // Display empty cells as '■'
}
System.out.println(); // Newline after each row
}
System.out.println(); // Extra newline for better readability
}
}
// Class to represent positions on the board (row and column)
class Node {
final int row, col; // Immutable row and column values
Node(int row, int col) {
this.row = row; // Initialize the row
this.col = col; // Initialize the column
}
}
4. Key Concepts Explained
- Grid Representation
The game grid is represented by a 2D character array, where:
'■'
indicates an empty cell.'.'
represents the snake’s body.'X'
marks food.
2. Snake Movement
The snake’s movement is controlled via keyboard inputs (U
for up, D
for down, L
for left, and R
for right).
3. Food Placement
Food is placed at random grid positions. If the snake eats the food, the game places new food and extends the snake’s length.
4. Collision Detection
The game ends if the snake runs into its body or moves outside the grid boundaries.
5. Features to Explore
- Dynamic Grid Resizing: Allow players to select grid size.
- Score Tracking: Keep a score based on the food consumed.
- Obstacles: Add walls or obstacles to make the game more challenging.
6. Running the Game
To run this game:
- Copy the code into your favorite Java IDE or editor.
- Compile and run the program.
- Use
U
,D
,L
, andR
to control the snake.
Final Thoughts
This simple Snake Game demonstrates the power of Java for building interactive applications. Once you’ve mastered the basics, add advanced features and make the game your own. Happy coding! 🎮