Arduino Snake Game with Joystick and OLED Display

This project involves creating a simple snake game using an Arduino, a joystick for controlling the snake, and an OLED display to show the game graphics. The game will use basic components, including a joystick module to control the snake’s movement and a OLED display to render the snake and the game environment.

Components Required:

  • Arduino Board (e.g., Arduino Uno or any compatible board)
  • Joystick Module (e.g., KY-023 or similar)
  • OLED Display (128×64, preferably I2C, e.g., SSD1306 OLED)
  • Breadboard and Jumper Wires
  • Push Button (Optional, to restart or pause the game)

Circuit Diagram:

  1. OLED Display:
    • Connect VCC to 5V (Arduino)
    • Connect GND to GND (Arduino)
    • Connect SDA to A4 (Arduino Uno)
    • Connect SCL to A5 (Arduino Uno)
  2. Joystick Module:
    • Connect VCC to 5V (Arduino)
    • Connect GND to GND (Arduino)
    • Connect VRX to A0 (Arduino)
    • Connect VRY to A1 (Arduino)
    • Connect SW (Switch) to any digital pin (e.g., D2)
  3. Optional Push Button (for pause/restart):
    • Connect one side of the button to a digital pin (e.g., D3)
    • Connect the other side to GND

Arduino Code:

#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

// Define screen dimensions
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
// Define the OLED reset pin (set to -1 if not connected)
#define OLED_RESET    -1
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

// Define joystick pins
#define JOY_X_PIN A0
#define JOY_Y_PIN A1
#define JOY_BTN_PIN 2  // Button on joystick for restart (optional)

// Snake game variables
int snakeX = 64, snakeY = 32;  // Snake starting position
int direction = 0;             // Initial direction (0: right, 1: down, 2: left, 3: up)
int snakeSize = 8;             // Increase snake size to 8x8 pixels

void setup() {
  // Initialize serial for debugging
  Serial.begin(9600);

  // Initialize OLED display
  if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
    Serial.println(F("SSD1306 allocation failed"));
    while (1);  // Infinite loop if OLED fails to initialize
  }

  // Clear the display
  display.clearDisplay();

  // Set up display parameters
  display.setTextSize(1);
  display.setTextColor(SSD1306_WHITE);
  display.setCursor(0, 0);
  display.print("Game Starting...");
  display.display();  // Update the screen with the starting text

  delay(1000);  // Wait for a second before starting the game
}

void loop() {
  // Read joystick for movement
  int joyXVal = analogRead(JOY_X_PIN);
  int joyYVal = analogRead(JOY_Y_PIN);

  // Set movement based on joystick position
  if (joyXVal < 400) {  // Move left
    if (direction != 0) direction = 2;
  }
  else if (joyXVal > 600) {  // Move right
    if (direction != 2) direction = 0;
  }

  if (joyYVal < 400) {  // Move up
    if (direction != 1) direction = 3;
  }
  else if (joyYVal > 600) {  // Move down
    if (direction != 3) direction = 1;
  }

  // Clear the display for the next frame
  display.clearDisplay();
  
  // Move the snake based on direction
  if (direction == 0) snakeX++;  // Move right
  if (direction == 1) snakeY++;  // Move down
  if (direction == 2) snakeX--;  // Move left
  if (direction == 3) snakeY--;  // Move up

  // Ensure snake stays within screen bounds
  snakeX = constrain(snakeX, 0, SCREEN_WIDTH - snakeSize);
  snakeY = constrain(snakeY, 0, SCREEN_HEIGHT - snakeSize);

  // Debug: print snake coordinates to serial monitor
  Serial.print("Snake Position: X=");
  Serial.print(snakeX);
  Serial.print(" Y=");
  Serial.println(snakeY);

  // Draw the snake (as a larger 8x8 block)
  display.fillRect(snakeX, snakeY, snakeSize, snakeSize, WHITE);  // Snake as an 8x8 rectangle
  
  // Display the changes
  display.display();

  // Delay for a brief moment to control speed of movement
  delay(50);  // Control the speed of movement
}

Explanation of the Code:

  1. Libraries:
    • Adafruit_GFX and Adafruit_SSD1306 are used to control the OLED display.
    • Wire is used for I2C communication between the Arduino and the OLED display.
  2. Joystick Handling:
    • The joystick’s X and Y axes are read using analogRead(). These values are used to determine the snake’s direction.
    • The button on the joystick can be used to reset the game.
  3. Snake Logic:
    • The snake is represented as an array of snakeX[] and snakeY[], which hold the X and Y coordinates of each segment.
    • The snake moves by shifting its body and updating the head based on the direction.
  4. Game Mechanics:
    • The snake grows when it eats food, and new food is randomly placed on the screen.
    • The game ends when the snake collides with the boundaries or itself.
  5. OLED Display:
    • The snake and food are drawn using the fillRect() function. The snake’s body is drawn as small blocks.
    • The game over message is displayed when the game ends.

Game Enhancements:

  • Difficulty Levels: Increase the speed of the snake as the score increases.
  • Score Display: Display the current score based on the length of the snake.
  • Pause Function: Add a feature to pause and resume the game using the joystick button.

With this setup, you can create a basic snake game that is fun to play and provides a great starting point for further enhancement.