Snake Game With Joystick

This code integrates a joystick with a simple Snake Game using the pygame library. It also utilizes the ACROME SMD platform to receive joystick inputs and provide feedback, like turning on a buzzer when food is consumed.

About Tools and Materials:

SMD Red (Purchase Here)

SMD USB Gateway (Purchase Here)

Arduino Gateway Module (Purchase Here)

Buzzer Module (Purchase Here)

Joystick Module (Purchase Here)

Step 1: Hardware & Software Overview

Key Component:

  1. Buzzer Module Every time the snake eats the food Buzzer Module makes a sound.

  2. Joystick Module Handles snake movement.

  3. pygame Handles the graphics and user interface for the snake game. It displays the snake, food, score, and manages input events.

  4. ACROME SMD Communicates with the joystick and handles joystick input as well as buzzer feedback.

Project Key Features:

  1. Joystick Input: The joystick connected via the ACROME SMD platform is used to control the snake's direction. The snake moves left, right, up, or down based on the joystick's X and Y-axis values. A button on the joystick can be used to pause and resume the game.

  2. Start and Game Over Menus: The game starts with a simple menu where you can choose to start the game or quit. If the game ends (snake hits a wall or itself), a game over menu is displayed, with options to retry or quit.

  3. Game Logic: The snake grows when it eats food, and the length is increased. The snake's movement speed is fixed but can be controlled by the joystick. A buzzer sound is triggered when the snake eats the food.

  4. Pause Functionality: A button on the joystick allows pausing and resuming the game.

Step 2: Assemble

Getting Started

  1. Hardware Setup

Project Wiring Diagram

Step 3: Run & Test

Start Menu: When the program is run, the start menu is displayed. The user can click on "Start" to begin the game or "Quit" to exit.

Snake Movement: During the game, the joystick's position controls the snake's movement. Moving the joystick in any direction updates the snake’s position.

Eating Food: When the snake's head collides with the food, the snake grows, and a buzzer sound is triggered.

Game Over: The game ends when the snake hits the boundaries or itself. A "Game Over" menu is displayed with options to retry or quit.

Pausing the Game: The game can be paused and resumed using the joystick's button

import pygame
import time
import random
from smd.red import *
from serial.tools.list_ports import comports
from platform import system

# SMD Module Settings
baudrate = 115200          # Baud rate for communication
ID = 0                     # SMD module ID
joystick_id = 5            # ID of the joystick module
button_id = 5              # ID of the button module
rgb_led_id = 5             # ID of the RGB LED module


def USB_Port():
    """
    Scans and identifies a compatible USB port for the current operating system.

    Returns:
        str: The detected USB port or None if no suitable port is found.
    """
    ports = list(comports())
    usb_names = {
        "Windows": ["USB Serial Port"],
        "Linux": ["/dev/ttyUSB"],
        "Darwin": [
            "/dev/tty.usbserial",
            "/dev/tty.usbmodem",
            "/dev/tty.SLAB_USBtoUART",
            "/dev/tty.wchusbserial",
            "/dev/cu.usbserial",
            "/dev/cu.usbmodem",
            "/dev/cu.SLAB_USBtoUART",
            "/dev/cu.wchusbserial",
        ]
    }

    os_name = system()
    if ports:
        for port in ports:
            if any(name in port.device or name in port.description for name in usb_names.get(os_name, [])):
                return port.device
        print("No suitable USB device found.")
    else:
        print("No ports detected!")
    return None


# Initialize SMD module
SerialPort = USB_Port()
if not SerialPort:
    raise Exception("No compatible USB port found. Please check your connection.")

master = Master(SerialPort, baudrate)
master.attach(Red(ID))
print("Connected Modules:", master.scan_modules(ID))


# Initialize Pygame
pygame.init()

# Define colors
white = (255, 255, 255)
yellow = (255, 255, 102)
black = (0, 0, 0)
red = (213, 50, 80)
green = (0, 255, 0)
blue = (50, 153, 213)

# Set display dimensions
width, height = 600, 400
display = pygame.display.set_mode((width, height))
pygame.display.set_caption('Snake Game')

# Clock to control game speed
clock = pygame.time.Clock()

# Snake settings
snake_block = 10
snake_speed = 15

# Font styles
font_style = pygame.font.SysFont("bahnschrift", 25)
score_font = pygame.font.SysFont("comicsansms", 35)


def display_score(score):
    """
    Displays the player's score on the screen.
    """
    value = score_font.render("Score: " + str(score), True, black)
    display.blit(value, [0, 0])


def draw_snake(snake_block, snake_list):
    """
    Draws the snake on the screen.

    Args:
        snake_block (int): The size of each block in the snake.
        snake_list (list): List of snake body parts' positions.
    """
    for x in snake_list:
        pygame.draw.rect(display, black, [x[0], x[1], snake_block, snake_block])


def message(msg, color, y_displace=0):
    """
    Displays a message on the screen.

    Args:
        msg (str): The message to display.
        color (tuple): The color of the message text.
        y_displace (int): Vertical displacement of the message.
    """
    mesg = font_style.render(msg, True, color)
    display.blit(mesg, [width / 6, height / 3 + y_displace])


def game_loop():
    """
    Main game loop for the Snake Game.
    """
    game_over = False
    close_game = False
    paused = False  # Pause state

    # Initial snake position and movement
    x1, y1 = width // 2, height // 2
    x1_change, y1_change = 0, 0

    # Snake body and food
    snake_list = []
    snake_length = 1
    food_x = round(random.randrange(0, width - snake_block) / 10.0) * 10.0
    food_y = round(random.randrange(0, height - snake_block) / 10.0) * 10.0

    while not game_over:
        while close_game:
            display.fill(blue)
            message("You Lost! Press Q to Quit or C to Play Again", red)
            display_score(snake_length - 1)
            pygame.display.update()

            for event in pygame.event.get():
                if event.type == pygame.KEYDOWN:
                    if event.key == pygame.K_q:
                        game_over = True
                        close_game = False
                    if event.key == pygame.K_c:
                        game_loop()

        # Check for button input to pause the game
        button_pressed = master.get_button(ID, button_id)
        if button_pressed == 1:
            paused = not paused
            time.sleep(0.5)  # Debounce delay

        while paused:
            # Display paused message
            display.fill(blue)
            message("Game Paused. Press Button to Resume", yellow)
            pygame.display.update()

            # Wait for button press to resume
            button_pressed = master.get_button(ID, button_id)
            if button_pressed == 1:
                paused = False
                time.sleep(0.5)  # Debounce delay

        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                game_over = True

        # Joystick control
        joystick = master.get_joystick(ID, joystick_id)
        if joystick:
            x_axis, y_axis = joystick[0], joystick[1]
            if x_axis < -50:  # Left
                x1_change, y1_change = -snake_block, 0
            elif x_axis > 50:  # Right
                x1_change, y1_change = snake_block, 0
            elif y_axis < -50:  # Up
                x1_change, y1_change = 0, -snake_block
            elif y_axis > 50:  # Down
                x1_change, y1_change = 0, snake_block

        x1 += x1_change
        y1 += y1_change

        # LED feedback
        if x1_change != 0 or y1_change != 0:
            master.set_rgb(ID, rgb_led_id, 0, 255, 0)  # Green LED for movement
        else:
            master.set_rgb(ID, rgb_led_id, 255, 0, 0)  # Red LED for no movement

        # Check for collision with boundaries
        if x1 >= width or x1 < 0 or y1 >= height or y1 < 0:
            close_game = True
            master.set_rgb(ID, rgb_led_id, 255, 0, 0)  # Red LED for game over

        display.fill(white)
        pygame.draw.rect(display, green, [food_x, food_y, snake_block, snake_block])

        # Update snake position
        snake_head = [x1, y1]
        snake_list.append(snake_head)
        if len(snake_list) > snake_length:
            del snake_list[0]

        # Check if the snake collides with itself
        for block in snake_list[:-1]:
            if block == snake_head:
                close_game = True
                master.set_rgb(ID, rgb_led_id, 255, 0, 0)  # Red LED for game over

        draw_snake(snake_block, snake_list)
        display_score(snake_length - 1)

        # Check if food is eaten
        if x1 == food_x and y1 == food_y:
            food_x = round(random.randrange(0, width - snake_block) / 10.0) * 10.0
            food_y = round(random.randrange(0, height - snake_block) / 10.0) * 10.0
            snake_length += 1
            master.set_rgb(ID, rgb_led_id, 0, 0, 255)  # Blue LED for eating
            time.sleep(0.2)  # Delay for visual effect

        pygame.display.update()
        clock.tick(snake_speed)

    pygame.quit()
    quit()


# Start the game loop
game_loop()

Conclusion: This is a fun and interactive way to use the ACROME SMD joystick to control the classic Snake game, providing a hardware-based gaming experience.

Last updated