Create Retro Snake Game With Arduino Nano and SSD130 OLED

by Skylar Jones in Circuits > Arduino

13 Views, 0 Favorites, 0 Comments

Create Retro Snake Game With Arduino Nano and SSD130 OLED

PCBX Simulation | Built a Retro Snake Game Circuit with PCBX and Here's What Happened!

The project utilizes an Arduino Nano in conjunction with an SSD1306 OLED display to create a Snake game interface. The SSD1306 OLED display serves as the visual component, showcasing the game's graphics. User interaction is facilitated by four buttons that control the direction of the snake's movement. The control unit for the project is the Arduino Development Board (ATmega328P).

Supplies

Arduino Nano R3

OLED Display0.66

Microchip ATmega328PB Microcontroller

PCBX Online Simulation

Circuit Connections

Snake Game.png

SSD1306 OLED Display:

  1. VCC is connected to the Arduino's 5V pin.
  2. GND is connected to the Arduino's GND pin.
  3. SCL is connected to the Arduino's A5 pin (SCL).
  4. SDA is connected to the Arduino's A4 pin (SDA).
  5. SSD1306 OLED Display: VCC is connected to the Arduino's 5V pin.GND is connected to the Arduino's GND pin.SCL is connected to the Arduino's A5 pin (SCL).SDA is connected to the Arduino's A4 pin (SDA).

Buttons:

  1. One terminal of each button is connected to specific digital input pins on the Arduino.
  2. The other terminal is connected to GND.
  3. To prevent signal bouncing, a 10kΩ pull-up resistor can be added between the button terminal and GND.
  4. Buttons: One terminal of each button is connected to specific digital input pins on the Arduino. The other terminal is connected to GND. To prevent signal bouncing, a 10kΩ pull-up resistor can be added between the button terminal and GND.


Description

贪吃蛇gif.gif

Including library files: At the beginning of the program, three library files are included for I2C communication, graphic display, and control of the OLED display.

Defining constants: Constants are defined for the size of the OLED display, the size of each snake block, and the maximum length of the snake.

OLED display initialization: The width, height, and I2C address of the OLED display are defined, and an Adafruit_SSD1306 object is created.

Initial positions of the snake and food: The initial position and direction of the snake, as well as the initial position variable for the food, are defined.

Button definition: The pin numbers for the buttons that control the snake's movement are defined.

Snake body array: A two-dimensional array is defined to store the position of each part of the snake's body.

setup() function: Initializes serial communication, the OLED display, and sets the button modes to input pull-up.

loop() function: The main loop of the program, is responsible for reading input, moving the snake, checking for collisions, drawing the screen, and controlling the game speed.

readInput() function: Reads button input and updates the snake's movement direction based on the button state.

moveSnake() function: Moves the snake according to the current direction and updates the position of each part of the snake's body.

increaseSnake() function: Increases the length of the snake when it eats food.

checkCollision() function: Checks if the snake has hit a boundary or its own body.

placeFood() function: Randomly places food on the screen, ensuring that it is not placed on the snake's body.

checkFoodCollision() function: Checks if the food collides with the snake's body.

drawScreen() function: Clears the screen and draws the snake and food.

displayGameOver() function: Displays "Game Over" information when the game ends and resets the game state.

Simulate Online

Project details here: https://www.pcbx.com/community-detail/7dd78acbf8c546319eda0409a003f23f

#include <Wire.h>

#include <Adafruit_GFX.h>

#include <Adafruit_SSD1306.h>



#define SCREEN_WIDTH 128 // OLED display width, in pixels

#define SCREEN_HEIGHT 64 // OLED display height, in pixels

#define SNAKE_BLOCK 2 // Size of each snake block

#define MAX_SNAKE_LENGTH 50



#define OLED_RESET -1 // Reset pin # (or -1 if sharing Arduino reset pin)

#define OLED_ADDRESS 0x3C // I2C address of the display

Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);



int snakeX = 32, snakeY = 32;

int dirX = 0, dirY = -SNAKE_BLOCK;



int foodX, foodY;



const int buttonUp = 2, buttonDown = 3, buttonLeft = 4, buttonRight = 5;



int snakeBody[MAX_SNAKE_LENGTH][2];

int snakeLength = 1;

int gameSpeed = 200;



void setup() {

Serial.begin(9600);

if(!display.begin(SSD1306_SWITCHCAPVCC, OLED_ADDRESS)) {

Serial.println(F("SSD1306 allocation failed"));

for(;;);

}

display.clearDisplay();



pinMode(buttonUp, INPUT_PULLUP);

pinMode(buttonDown, INPUT_PULLUP);

pinMode(buttonLeft, INPUT_PULLUP);

pinMode(buttonRight, INPUT_PULLUP);



snakeBody[0][0] = snakeX;

snakeBody[0][1] = snakeY;



placeFood();

}



void loop() {

readInput();



moveSnake();



if (snakeX == foodX && snakeY == foodY) {

increaseSnake();

placeFood();

gameSpeed = max(50, gameSpeed - 10);

}



if (checkCollision()) {

displayGameOver();

return; // End the current loop cycle to avoid extra drawing and updating

}



drawScreen();



delay(gameSpeed);

}



void readInput() {

if (digitalRead(buttonUp) == LOW && dirY != SNAKE_BLOCK) {

dirX = 0; dirY = -SNAKE_BLOCK;

}

if (digitalRead(buttonDown) == LOW && dirY != -SNAKE_BLOCK) {

dirX = 0; dirY = SNAKE_BLOCK;

}

if (digitalRead(buttonLeft) == LOW && dirX != SNAKE_BLOCK) {

dirX = -SNAKE_BLOCK; dirY = 0;

}

if (digitalRead(buttonRight) == LOW && dirX != -SNAKE_BLOCK) {

dirX = SNAKE_BLOCK; dirY = 0;

}

}



void moveSnake() {

int prevX = snakeX, prevY = snakeY;

snakeX += dirX;

snakeY += dirY;



for (int i = snakeLength - 1; i > 0; i--) {

snakeBody[i][0] = snakeBody[i - 1][0];

snakeBody[i][1] = snakeBody[i - 1][1];

}



snakeBody[0][0] = snakeX;

snakeBody[0][1] = snakeY;

}



void increaseSnake() {

if (snakeLength < MAX_SNAKE_LENGTH) {

snakeLength++;

}

}



bool checkCollision() {

if (snakeX < 0 || snakeX >= SCREEN_WIDTH || snakeY < 0 || snakeY >= SCREEN_HEIGHT) {

return true;

}



for (int i = 1; i < snakeLength; i++) {

if (snakeX == snakeBody[i][0] && snakeY == snakeBody[i][1]) {

return true;

}

}



return false;

}



void placeFood() {

do {

foodX = (random(0, SCREEN_WIDTH / SNAKE_BLOCK) * SNAKE_BLOCK);

foodY = (random(0, SCREEN_HEIGHT / SNAKE_BLOCK) * SNAKE_BLOCK);

} while (checkFoodCollision());

}



bool checkFoodCollision() {

for (int i = 0; i < snakeLength; i++) {

if (foodX == snakeBody[i][0] && foodY == snakeBody[i][1]) {

return true;

}

}

return false;

}



void drawScreen() {

display.clearDisplay();



for (int i = 0; i < snakeLength; i++) {

display.fillRect(snakeBody[i][0], snakeBody[i][1], SNAKE_BLOCK, SNAKE_BLOCK, SSD1306_WHITE);

}



display.fillRect(foodX, foodY, SNAKE_BLOCK, SNAKE_BLOCK, SSD1306_WHITE);



display.display();

}



void displayGameOver() {

display.clearDisplay();

display.setTextSize(2);

display.setTextColor(SSD1306_WHITE);

display.setCursor(0, 0);

display.println("Game Over");

display.display();

delay(2000);



snakeLength = 1;

snakeX = 32;

snakeY = 32;

dirX = 0;

dirY = -SNAKE_BLOCK;

gameSpeed = 200;



snakeBody[0][0] = snakeX;

snakeBody[0][1] = snakeY;



placeFood();

}

Conclusion

While the 3D simulation feature is still a work in progress, we would love to hear your suggestions and expectations. It's an open-source community; any sharing and feedback is welcome.

Your feedback will help our engineering team enhance the platform and better serve our users.

Join the PCBX Simulation Community and create your own project to win a surprise bag now.