How to Build a Snake Game in Python Using Pygame (Complete Tutorial with Source Code)

How to Build a Snake Game in Python Using Pygame

How to Build a Snake Game in Python Using Pygame thumbnail

The Snake Game is one of the most popular beginner-friendly game development projects. It teaches important programming concepts such as game loops, keyboard input, collision detection, score management, and event handling.

In this tutorial, we'll build a complete Snake Game using Python and the Pygame library. The game includes:

  • Moving snake
  • Random food generation
  • Score counter
  • Collision detection
  • Game Over screen
  • Restart option
  • On-screen mouse control buttons

Prerequisites

Before starting, make sure Python is installed.

Note: The original, upstream Pygame project has not yet released official pre-compiled wheels for Python 3.14. If you attempt to install it via pip install pygame under Python 3.14, your build will likely fail with a metadata or local compilation error because the required C extensions are not pre-built for this version.

Recommended Option: Pygame Community Edition (Pygame-CE)

Install Pygame using:

pip install pygame
//For Python 3.14
pip install pygame-ce

Project Overview

The game window is divided into small square cells. The snake moves one cell at a time. Whenever it eats food:

  • The snake grows longer.
  • The score increases.
  • New food appears at a random location.

The game ends if the snake:

  • Hits the wall
  • Hits its own body

Import Required Modules

import pygame
import random

pygame.init()

Explanation

  • pygame creates the game window, graphics, keyboard input, and sounds.
  • random places food at random positions.
  • pygame.init() initializes every required Pygame module.

Create Game Constants

WIDTH, HEIGHT = 600, 400
CELL = 20
FPS = 10

Explanation

These constants define the game configuration.

Constant Description
WIDTH Game window width
HEIGHT Game window height
CELL Size of each snake block
FPS Game speed

Define Colors

BLACK = (0,0,0)
GREEN = (0,255,0)
RED = (255,0,0)
WHITE = (255,255,255)
GRAY = (80,80,80)

RGB values are used to draw the snake, food, buttons, and text.


Create the Game Window

screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("Snake Game")

This creates the main window where everything is drawn.


Create the Clock

clock = pygame.time.Clock()
font = pygame.font.SysFont(None,30)

The clock controls the frame rate. The font object is used for displaying the score and game over message.


Create On-Screen Control Buttons

BUTTON_SIZE = 40

up_button = pygame.Rect(...)
down_button = pygame.Rect(...)
left_button = pygame.Rect(...)
right_button = pygame.Rect(...)

Why Use Buttons?

  • Works with mouse clicks
  • Useful for touch screens
  • Makes the game easier to play without a keyboard

Generate Random Food

def spawn_food(snake):
    while True:
        x = random.randrange(0, WIDTH, CELL)
        y = random.randrange(0, HEIGHT, CELL)

        if [x, y] not in snake:
            return [x, y]

How It Works

  • Selects a random grid position.
  • Checks whether the snake already occupies that cell.
  • If the location is free, food is created there.

Reset the Game

def reset():
    snake = [
        [100,100],
        [80,100],
        [60,100]
    ]

    direction = "RIGHT"
    food = spawn_food(snake)
    score = 0

    return snake, direction, food, score

Whenever a new game starts, this function creates a fresh snake, score, direction, and food.


Main Game Loop

while running:

Every Pygame application continuously runs inside a game loop. Each iteration performs four important tasks:

  1. Read user input
  2. Update the game
  3. Draw everything
  4. Repeat

Keyboard Controls

The game listens for arrow keys.

if event.key == pygame.K_UP:
    direction = "UP"

The snake cannot instantly move in the opposite direction because that would immediately collide with itself.


Mouse Controls

elif event.type == pygame.MOUSEBUTTONDOWN:

When the player clicks one of the arrow buttons, the direction changes.

  • Up Button → Move Up
  • Down Button → Move Down
  • Left Button → Move Left
  • Right Button → Move Right

Move the Snake

The snake's head moves one cell depending on the current direction.

head = snake[0].copy()

A copy of the head is created before updating its coordinates.


Collision Detection

The game checks whether the snake:

  • Leaves the window
  • Touches its own body
if head in snake:
    game_over = True

Eating Food

if head == food:
    score += 1
    food = spawn_food(snake)

When the snake reaches the food:

  • Score increases.
  • The snake grows.
  • New food appears randomly.

Drawing the Snake

pygame.draw.rect(
    screen,
    GREEN,
    (segment[0], segment[1], CELL, CELL)
)

Each snake segment is drawn as a green square.


Drawing the Food

pygame.draw.rect(screen, RED,
(food[0], food[1], CELL, CELL))

The food is displayed as a red square.


Display the Score

score_text = font.render(
    f"Score: {score}",
    True,
    WHITE
)

The current score is always shown at the top-left corner.


Draw On-Screen Buttons

Four rounded buttons are drawn using pygame.Rect() and pygame.draw.rect().

Arrow symbols are displayed using the font renderer.


Game Over Screen

When the player loses, the following message appears:

  • GAME OVER
  • Press SPACE to Restart

Pressing the Space key calls the reset() function to start a new game.


Complete Features

  • Grid-based movement
  • Keyboard controls
  • Mouse controls
  • Random food spawning
  • Score tracking
  • Snake growth
  • Wall collision detection
  • Self collision detection
  • Restart functionality
  • Clean and beginner-friendly code

Final Complete Source Code

import pygame
import random

pygame.init()

# -------------------------------
# Constants
# -------------------------------
WIDTH, HEIGHT = 600, 400
CELL = 20
FPS = 10

# Colors
BLACK = (0, 0, 0)
GREEN = (0, 255, 0)
RED = (255, 0, 0)
WHITE = (255, 255, 255)
GRAY = (80, 80, 80)

# -------------------------------
# Create Window
# -------------------------------
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("Snake Game")

clock = pygame.time.Clock()
font = pygame.font.SysFont(None, 30)

# -------------------------------
# Control Buttons
# -------------------------------
BUTTON_SIZE = 40

up_button = pygame.Rect(500, 230, BUTTON_SIZE, BUTTON_SIZE)
down_button = pygame.Rect(500, 320, BUTTON_SIZE, BUTTON_SIZE)
left_button = pygame.Rect(450, 275, BUTTON_SIZE, BUTTON_SIZE)
right_button = pygame.Rect(550, 275, BUTTON_SIZE, BUTTON_SIZE)


# -------------------------------
# Functions
# -------------------------------
def spawn_food(snake):
    while True:
        x = random.randrange(0, WIDTH, CELL)
        y = random.randrange(0, HEIGHT, CELL)

        if [x, y] not in snake:
            return [x, y]


def reset():
    snake = [
        [100, 100],
        [80, 100],
        [60, 100]
    ]

    direction = "RIGHT"
    food = spawn_food(snake)
    score = 0

    return snake, direction, food, score


# -------------------------------
# Game Variables
# -------------------------------
snake, direction, food, score = reset()

running = True
game_over = False

# -------------------------------
# Game Loop
# -------------------------------
while running:

    # ---------------------------
    # Events
    # ---------------------------
    for event in pygame.event.get():

        if event.type == pygame.QUIT:
            running = False

        elif event.type == pygame.KEYDOWN:

            if game_over:

                if event.key == pygame.K_SPACE:
                    snake, direction, food, score = reset()
                    game_over = False

            else:

                if event.key == pygame.K_UP and direction != "DOWN":
                    direction = "UP"

                elif event.key == pygame.K_DOWN and direction != "UP":
                    direction = "DOWN"

                elif event.key == pygame.K_LEFT and direction != "RIGHT":
                    direction = "LEFT"

                elif event.key == pygame.K_RIGHT and direction != "LEFT":
                    direction = "RIGHT"

        elif event.type == pygame.MOUSEBUTTONDOWN:

            pos = pygame.mouse.get_pos()

            if up_button.collidepoint(pos) and direction != "DOWN":
                direction = "UP"

            elif down_button.collidepoint(pos) and direction != "UP":
                direction = "DOWN"

            elif left_button.collidepoint(pos) and direction != "RIGHT":
                direction = "LEFT"

            elif right_button.collidepoint(pos) and direction != "LEFT":
                direction = "RIGHT"

    # ---------------------------
    # Move Snake
    # ---------------------------
    if not game_over:

        head = snake[0].copy()

        if direction == "UP":
            head[1] -= CELL

        elif direction == "DOWN":
            head[1] += CELL

        elif direction == "LEFT":
            head[0] -= CELL

        elif direction == "RIGHT":
            head[0] += CELL

        # Collision
        if (
            head[0] < 0
            or head[0] >= WIDTH
            or head[1] < 0
            or head[1] >= HEIGHT
            or head in snake
        ):
            game_over = True

        else:

            snake.insert(0, head)

            if head == food:
                score += 1
                food = spawn_food(snake)
            else:
                snake.pop()

    # ---------------------------
    # Draw
    # ---------------------------
    screen.fill(BLACK)

    # Food
    pygame.draw.rect(screen, RED, (food[0], food[1], CELL, CELL))

    # Snake
    for segment in snake:
        pygame.draw.rect(
            screen,
            GREEN,
            (segment[0], segment[1], CELL, CELL)
        )

    # Score
    score_text = font.render(f"Score: {score}", True, WHITE)
    screen.blit(score_text, (10, 10))

    # ---------------------------
    # Draw Control Buttons
    # ---------------------------
    pygame.draw.rect(screen, GRAY, up_button, border_radius=8)
    pygame.draw.rect(screen, GRAY, down_button, border_radius=8)
    pygame.draw.rect(screen, GRAY, left_button, border_radius=8)
    pygame.draw.rect(screen, GRAY, right_button, border_radius=8)

    screen.blit(font.render("↑", True, WHITE), (510, 235))
    screen.blit(font.render("↓", True, WHITE), (510, 325))
    screen.blit(font.render("←", True, WHITE), (460, 280))
    screen.blit(font.render("→", True, WHITE), (560, 280))

    # ---------------------------
    # Game Over
    # ---------------------------
    if game_over:

        game_over_text = font.render("GAME OVER", True, WHITE)
        restart_text = font.render("Press SPACE to Restart", True, WHITE)

        screen.blit(
            game_over_text,
            (
                WIDTH // 2 - game_over_text.get_width() // 2,
                HEIGHT // 2 - 20,
            ),
        )

        screen.blit(
            restart_text,
            (
                WIDTH // 2 - restart_text.get_width() // 2,
                HEIGHT // 2 + 15,
            ),
        )

    pygame.display.flip()
    clock.tick(FPS)

pygame.quit()

Output:

Snake Game in Python Using Pygame Screenshot

Possible Improvements

  • Add background music
  • Add sound effects
  • Store high scores
  • Add pause button
  • Multiple difficulty levels
  • Animated snake head
  • Power-up items
  • Obstacles
  • Touch controls for mobile
  • Game menu

Conclusion

Congratulations! You have built a complete Snake Game using Python and Pygame. Along the way, you learned how to create a game loop, handle keyboard and mouse input, detect collisions, generate random objects, update scores, and render graphics in real time. This project provides a strong foundation for building more advanced 2D games with Python.


Frequently Asked Questions (FAQ)

1. Is Pygame suitable for beginners?

Yes. Pygame is one of the easiest libraries for learning game development in Python.

2. Can I add sound effects?

Yes. You can use pygame.mixer.Sound() to play sound effects and background music.

3. Why does the snake move on a grid?

Grid-based movement simplifies collision detection and makes gameplay predictable.

4. How can I increase the game speed?

Increase the value of the FPS constant to make the snake move faster.

5. Can this game run on Windows, macOS, and Linux?

Yes. Pygame is cross-platform and works on all major desktop operating systems.

Previous Post Next Post

Contact Form