How to Create a Python Snake Game With Pygame

Introduction

Snake game is a classic arcade game that originated in the late 1970s. It gained popularity in the 1990s when it was pre-installed on Nokia mobile phones. In the game, the player controls a snake that moves around a bounded area, such as a rectangular grid. The snake grows in length as it consumes food items randomly placed on the grid. The objective is to eat as much food as possible without colliding with the walls of the grid or the snake’s own body. The game becomes progressively challenging as the snake grows longer, making it harder to maneuver without crashing.

Today, in this comprehensive tutorial, we embark on an exciting journey to craft our very own Snake game using Pygame.

Setting Up Your Environment and Installing Dependencies

To begin creating the Snake game with Pygame, we’ll set up a virtual environment to manage our project dependencies. Using a virtual environment ensures that our project’s dependencies are isolated from the system-wide Python installation, providing better dependency management and avoiding conflicts between different projects.

Firstly, we’ll create a virtual environment by running the following command in our terminal or command prompt.

Bash
$ python3 -m venv snake_venv

This command creates a virtual environment named snake_venv in the current directory. We can activate the virtual environment using platform-specific commands.

  • On Windows
Bash
$ snake_venv\Scripts\activate
  • On macOS and Linux
Bash
source snake_venv/bin/activate

Once the virtual environment is activated, we can proceed to install the required module, Pygame. Pygame is a set of Python modules designed for writing video games. We’ll install it using pip, Python’s package manager.

Bash
pip install pygame

Now that Pygame is installed, we’re prepared to craft the Python script for our Snake game. Let’s proceed by creating a Python file, such as snake_game.py, within our project directory.

Initializing Pygame

import pygame
import random

# Initialize Pygame
pygame.init()

# Set up the screen
screen_width = 800
screen_height = 600
cell_size = 20
grid_width = screen_width // cell_size
grid_height = screen_height // cell_size
screen = pygame.display.set_mode((screen_width, screen_height))
pygame.display.set_caption("Snake Game")

This Python code imports the Pygame library, essential for developing 2D games, and the random module for generating random numbers. Following this, the code initializes Pygame with pygame.init(). It then sets up the game screen by defining variables such as screen_width and screen_height to determine the dimensions of the window, cell_size to specify the size of each cell in the game grid, and calculates the number of cells horizontally and vertically using grid_width and grid_height. Finally, it creates the game window using pygame.display.set_mode() with the specified dimensions and sets the title of the window to “Snake Game” using pygame.display.set_caption(). This groundwork establishes the basic framework for the Snake game, preparing the environment for further development and implementation of game mechanics.

Defining Colors

white = (255, 255, 255)
black = (0, 0, 0)
green = (0, 255, 0)
red = (255, 0, 0)

In our Pygame development, colors play crucial roles in setting the tone. White (255, 255, 255) provides a pristine canvas, while black (0, 0, 0) adds depth. Green (0, 255, 0) symbolizes vitality, and red (255, 0, 0) signifies both sustenance and danger. Together, they weave a vibrant tapestry in our Snake game, engaging players in a visually immersive experience.

Creating the Snake Class

class Snake:
    def __init__(self):
        self.length = 1
        self.positions = [((screen_width / 2), (screen_height / 2))]
        self.direction = random.choice([(0, -1), (0, 1), (-1, 0), (1, 0)])  # Directions are stored as tuples
        self.color = green

    def get_head_position(self):
        return self.positions[0]

    def turn(self, point):
        if self.length > 1 and (point[0] * -1, point[1] * -1) == self.direction:
            return
        else:
            self.direction = point

    def move(self):
        cur = self.get_head_position()
        x, y = self.direction  # Now it's safe to unpack direction
        new = (((cur[0] + (x * cell_size)) % screen_width), (cur[1] + (y * cell_size)) % screen_height)
        if len(self.positions) > 2 and new in self.positions[2:]:
            return True  # Game over
        else:
            self.positions.insert(0, new)
            if len(self.positions) > self.length:
                self.positions.pop()

    def reset(self):
        self.length = 1
        self.positions = [((screen_width / 2), (screen_height / 2))]
        self.direction = random.choice([(0, -1), (0, 1), (-1, 0), (1, 0)])  # Reset direction randomly

    def draw(self, surface):
        for p in self.positions:
            r = pygame.Rect((p[0], p[1]), (cell_size, cell_size))
            pygame.draw.rect(surface, self.color, r)
            pygame.draw.rect(surface, black, r, 1)

    def handle_keys(self):
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
            elif event.type == pygame.KEYDOWN:
                if event.key == pygame.K_q:
                    pygame.quit()
                elif event.key == pygame.K_UP:
                    self.turn((0, -1))
                elif event.key == pygame.K_DOWN:
                    self.turn((0, 1))
                elif event.key == pygame.K_LEFT:
                    self.turn((-1, 0))
                elif event.key == pygame.K_RIGHT:
                    self.turn((1, 0))

The Snake class encapsulates the functionality and behavior of the snake entity within our game. Upon initialization, it sets the snake’s initial length, position, direction, and color. The get_head_position method retrieves the position of the snake’s head. turn allows the snake to change direction based on user input, ensuring it doesn’t reverse direction. The move method controls the snake’s movement, updating its position while handling collision detection. If the snake collides with itself, the game ends. The reset method restores the snake to its initial state. draw renders the snake onto the game surface, drawing each segment with its assigned color. Finally, handle_keys processes user input to change the snake’s direction, allowing players to navigate the game environment using arrow keys.

Creating the Food Class

class Food:
    def __init__(self):
        self.position = (0, 0)
        self.color = red
        self.randomize_position()

    def randomize_position(self):
        self.position = (random.randint(0, grid_width-1) * cell_size, random.randint(0, grid_height-1) * cell_size)

    def draw(self, surface):
        r = pygame.Rect((self.position[0], self.position[1]), (cell_size, cell_size))
        pygame.draw.rect(surface, self.color, r)
        pygame.draw.rect(surface, black, r, 1)

The Food class is responsible for managing the food items that appear within the game. Upon initialization, each food item is assigned a default position at coordinates (0, 0) and a color, typically represented by the red hue. The randomize_position method ensures that each food item spawns at a random location within the game grid, ensuring variety and unpredictability in gameplay. When drawn onto the game surface, each food item is represented by a rectangular shape, filled with the assigned color. Additionally, a black outline is drawn around the food item to provide visual contrast and definition, enhancing its visibility within the game environment.

Displaying Game Over Message

def display_game_over(score):
    font = pygame.font.SysFont(None, 48)
    game_over_text = font.render("Game Over!", True, white)
    score_text = font.render(f"Your score: {score}", True, white)
    screen.blit(game_over_text, (screen_width // 2 - game_over_text.get_width() // 2, screen_height // 2 - game_over_text.get_height() // 2 - 50))
    screen.blit(score_text, (screen_width // 2 - score_text.get_width() // 2, screen_height // 2 - score_text.get_height() // 2 + 50))
    pygame.display.update()
    pygame.time.wait(2000)

The display_game_over function is responsible for presenting the game over message along with the player’s score upon the conclusion of the game. Firstly, it creates a font object with a size of 48 pixels, allowing for clear and legible text rendering. Using this font, it generates two text surfaces: one displaying “Game Over!” and the other showing the player’s score. These text surfaces are rendered in white color to ensure visibility against the game background. The script.blit() function is then used to draw these text surfaces onto the game screen at appropriate positions. Finally, the updated display is presented to the player, and the function pauses for 2000 milliseconds to allow the player to acknowledge the game’s conclusion before proceeding.

Main Game Loop

def main():
    # Game objects
    snake = Snake()
    food = Food()

    clock = pygame.time.Clock()
    score = 0

    while True:
        game_over = False

        screen.fill(black)  # Set background color to black

        # Handle events
        snake.handle_keys()
        game_over = snake.move()

        if game_over:
            display_game_over(score)
            break

        if snake.get_head_position() == food.position:
            snake.length += 1
            score += 1
            food.randomize_position()

        snake.draw(screen)
        food.draw(screen)

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

if __name__ == "__main__":
    main()

In this segment of the Snake game code, the main function serves as the central control hub for orchestrating the game’s flow and mechanics. Within this function, several key operations are carried out to ensure smooth gameplay.

Firstly, the function initializes essential game objects, creating instances of the Snake and Food classes, which represent the player-controlled snake and the food items, respectively. Additionally, it creates a game clock using Pygame’s Clock object to regulate the game’s frame rate.

The function enters into a continuous loop where the game’s state is updated and rendered on the screen repeatedly. Within this loop, the screen is filled with a black background color to provide contrast for the game elements.

User input is handled through the handle_keys method of the Snake class, allowing players to control the snake’s movement using arrow keys or other specified controls.

The move method of the Snake class is called to update the snake’s position and detect collisions with itself or the game boundaries. If a collision occurs, the game over state is triggered, and the loop is exited.

If the snake’s head position coincides with the position of the food item, the snake’s length is increased, and the player’s score is incremented. The food item is then moved to a new random position within the game grid.

After each iteration of the game loop, the snake and food elements are drawn onto the screen using their respective draw methods, ensuring that the player’s actions and the game state are visually represented.

Finally, the display is updated to reflect any changes made during the loop, and the game clock regulates the frame rate to maintain a consistent and smooth gaming experience.

Overall, this main function encapsulates the core gameplay mechanics of the Snake game, seamlessly integrating user input, game logic, and visual rendering to deliver an engaging and interactive gaming experience.

Running The Script

To run the Snake game script, navigate to the directory containing the Python script file (e.g., snake_game.py) using your terminal or command prompt. Then, execute the script by typing python3 snake_game.py and pressing Enter.

Bash
$ python3 snake_game.py

This will launch the game window, allowing you to play the Snake game. Use the arrow keys or designated controls to move the snake and eat the food items while avoiding collisions with the walls and the snake’s own body.

snake_game.py

Access the complete source code on GitHub and immerse yourself in the timeless arcade adventure, powered by Python and Pygame!


DarkLight
×