Build a Snake Game in Python with Turtle

Published on: July 10, 2026
Reading time: 6 minutes
Ilustração de uma cobra com o logo do Python centralizado

Building a classic game is one of the best ways to turn Python fundamentals into a complete project. A Snake game in Python combines variables, functions, keyboard events, lists, coordinates, collision detection, and a game loop in a result you can see and play.

In this tutorial, you will build Snake with Python’s standard turtle module. The snake moves across a grid, grows when it reaches food, earns points, and restarts when it hits a wall or its own body. You do not need to install an external package.

The project is beginner-friendly, but it also introduces patterns used in larger games: separate objects, controlled frame updates, input handlers, state management, and collision rules. After finishing it, you can compare the approach with Pygame for beginners and decide which library fits your next project.

How the Snake Game Works

The game contains five main parts:

  • A window that displays the game.
  • A head that moves one grid cell at a time.
  • Food placed at a random grid position.
  • Body segments that follow the previous segment.
  • Rules for scoring, wall collisions, and self-collisions.

The coordinate system places the center of the window at (0, 0). Positive x-values move right, negative x-values move left, positive y-values move up, and negative y-values move down. We will use a grid size of 20 pixels so the snake and food always align.

Why Use Turtle for a Beginner Snake Game?

turtle is included with many Python installations and provides immediate visual feedback. It can create multiple drawable objects, listen for keyboard events, update a screen, and schedule repeated functions. That makes it suitable for learning game logic without first learning a larger framework.

The official Python turtle documentation explains the object-oriented interface used in this project. Food placement uses the standard random module.

Turtle is ideal for small educational games. For smoother animation, sound, sprites, or larger projects, the batch companion guide on building games with Pygame is the natural next step.

Project Setup

Create a file named snake_game.py. The first step imports the modules and defines constants:

import random
import turtle

WIDTH = 600
HEIGHT = 600
STEP = 20
DELAY_MS = 100

Constants keep important values in one place. Changing DELAY_MS changes the game speed. Changing STEP changes the grid size, although the snake and food sizes should remain consistent with it.

Create the Game Window

screen = turtle.Screen()
screen.title("Snake Game in Python")
screen.bgcolor("#111827")
screen.setup(width=WIDTH, height=HEIGHT)
screen.tracer(0)

screen.tracer(0) disables automatic drawing updates. We will call screen.update() once per frame, which avoids visible flickering and gives the program control over when the scene is redrawn.

Create the Snake Head

head = turtle.Turtle()
head.shape("square")
head.color("#22c55e")
head.penup()
head.goto(0, 0)
head.direction = "stop"

penup() prevents the turtle from drawing a line while it moves. The custom direction attribute stores the current movement state.

Handle Keyboard Input

Four functions change direction. Each function prevents an immediate 180-degree turn because that would make the head collide with the first body segment.

def go_up():
    if head.direction != "down":
        head.direction = "up"


def go_down():
    if head.direction != "up":
        head.direction = "down"


def go_left():
    if head.direction != "right":
        head.direction = "left"


def go_right():
    if head.direction != "left":
        head.direction = "right"

Bind the functions to the arrow keys:

screen.listen()
screen.onkeypress(go_up, "Up")
screen.onkeypress(go_down, "Down")
screen.onkeypress(go_left, "Left")
screen.onkeypress(go_right, "Right")

Event-handler functions normally receive no argument here. Their job is to update state; the main frame function performs the movement. This separation keeps input and game logic easier to understand.

Move the Snake on a Grid

def move_head():
    x = head.xcor()
    y = head.ycor()

    if head.direction == "up":
        head.sety(y + STEP)
    elif head.direction == "down":
        head.sety(y - STEP)
    elif head.direction == "left":
        head.setx(x - STEP)
    elif head.direction == "right":
        head.setx(x + STEP)

The function changes one coordinate by exactly 20 pixels. The Python conditional expressions guide can help with short decisions, but ordinary if/elif blocks are clearer for mutually exclusive directions.

Create and Reposition the Food

food = turtle.Turtle()
food.shape("circle")
food.color("#ef4444")
food.penup()
food.goto(100, 0)


def random_grid_position():
    horizontal_cells = (WIDTH // 2 - STEP) // STEP
    vertical_cells = (HEIGHT // 2 - STEP) // STEP

    x = random.randint(-horizontal_cells, horizontal_cells) * STEP
    y = random.randint(-vertical_cells, vertical_cells) * STEP
    return x, y

Multiplying a random integer by STEP guarantees that food appears on the same grid as the snake. The function demonstrates a useful Python return statement that sends two coordinates back as a tuple.

Grow the Snake Body

Store body segments in a list. When the snake eats food, create a new square and append it:

segments = []


def add_segment():
    segment = turtle.Turtle()
    segment.shape("square")
    segment.color("#86efac")
    segment.penup()
    segment.goto(1000, 1000)
    segments.append(segment)

Before moving the head, move each segment to the previous segment’s old position. Iterate backward so you do not overwrite a position before the next segment can use it.

def move_segments():
    for index in range(len(segments) - 1, 0, -1):
        previous_x = segments[index - 1].xcor()
        previous_y = segments[index - 1].ycor()
        segments[index].goto(previous_x, previous_y)

    if segments:
        segments[0].goto(head.xcor(), head.ycor())

Backward iteration is a useful pattern whenever each item depends on the state of the item before it. For other iteration tools, see the Python itertools beginner guide.

Add the Score Display

score = 0
high_score = 0

score_writer = turtle.Turtle()
score_writer.hideturtle()
score_writer.color("white")
score_writer.penup()
score_writer.goto(0, HEIGHT // 2 - 45)


def update_score():
    score_writer.clear()
    score_writer.write(
        f"Score: {score}   High score: {high_score}",
        align="center",
        font=("Arial", 18, "normal"),
    )

The score variables belong to the game state. In a larger project, you could group state inside a class or a Python dataclass.

Detect Food, Walls, and the Snake Body

Turtle’s distance() method makes food and body collisions easy. For walls, compare the head coordinates with the playable boundaries.

def hit_wall():
    horizontal_limit = WIDTH // 2 - STEP
    vertical_limit = HEIGHT // 2 - STEP

    return (
        abs(head.xcor()) > horizontal_limit
        or abs(head.ycor()) > vertical_limit
    )


def hit_body():
    return any(head.distance(segment) < STEP for segment in segments)

any() stops as soon as one segment is close enough to count as a collision. This is more expressive than managing a separate Boolean flag manually.

Reset the Game Safely

def reset_game():
    global score, high_score

    if score > high_score:
        high_score = score

    score = 0
    head.goto(0, 0)
    head.direction = "stop"

    for segment in segments:
        segment.goto(1000, 1000)

    segments.clear()
    update_score()

The off-screen move hides old segments before the list is cleared. The high score remains available until the program closes.

Build the Frame Function

Instead of using a blocking infinite loop, schedule the next frame with screen.ontimer(). This allows Turtle’s event system to keep processing keyboard and window events.

def game_frame():
    global score

    move_segments()
    move_head()

    if head.distance(food) < STEP:
        food.goto(random_grid_position())
        add_segment()
        score += 10
        update_score()

    if hit_wall() or hit_body():
        reset_game()

    screen.update()
    screen.ontimer(game_frame, DELAY_MS)

Complete Snake Game Code

import random
import turtle

WIDTH = 600
HEIGHT = 600
STEP = 20
DELAY_MS = 100

screen = turtle.Screen()
screen.title("Snake Game in Python")
screen.bgcolor("#111827")
screen.setup(width=WIDTH, height=HEIGHT)
screen.tracer(0)

head = turtle.Turtle()
head.shape("square")
head.color("#22c55e")
head.penup()
head.goto(0, 0)
head.direction = "stop"

food = turtle.Turtle()
food.shape("circle")
food.color("#ef4444")
food.penup()
food.goto(100, 0)

segments = []
score = 0
high_score = 0

score_writer = turtle.Turtle()
score_writer.hideturtle()
score_writer.color("white")
score_writer.penup()
score_writer.goto(0, HEIGHT // 2 - 45)


def update_score():
    score_writer.clear()
    score_writer.write(
        f"Score: {score}   High score: {high_score}",
        align="center",
        font=("Arial", 18, "normal"),
    )


def go_up():
    if head.direction != "down":
        head.direction = "up"


def go_down():
    if head.direction != "up":
        head.direction = "down"


def go_left():
    if head.direction != "right":
        head.direction = "left"


def go_right():
    if head.direction != "left":
        head.direction = "right"


def move_head():
    x = head.xcor()
    y = head.ycor()

    if head.direction == "up":
        head.sety(y + STEP)
    elif head.direction == "down":
        head.sety(y - STEP)
    elif head.direction == "left":
        head.setx(x - STEP)
    elif head.direction == "right":
        head.setx(x + STEP)


def move_segments():
    for index in range(len(segments) - 1, 0, -1):
        segments[index].goto(
            segments[index - 1].xcor(),
            segments[index - 1].ycor(),
        )

    if segments:
        segments[0].goto(head.xcor(), head.ycor())


def add_segment():
    segment = turtle.Turtle()
    segment.shape("square")
    segment.color("#86efac")
    segment.penup()
    segment.goto(1000, 1000)
    segments.append(segment)


def random_grid_position():
    horizontal_cells = (WIDTH // 2 - STEP) // STEP
    vertical_cells = (HEIGHT // 2 - STEP) // STEP
    return (
        random.randint(-horizontal_cells, horizontal_cells) * STEP,
        random.randint(-vertical_cells, vertical_cells) * STEP,
    )


def hit_wall():
    return (
        abs(head.xcor()) > WIDTH // 2 - STEP
        or abs(head.ycor()) > HEIGHT // 2 - STEP
    )


def hit_body():
    return any(head.distance(segment) < STEP for segment in segments)


def reset_game():
    global score, high_score

    high_score = max(high_score, score)
    score = 0
    head.goto(0, 0)
    head.direction = "stop"

    for segment in segments:
        segment.goto(1000, 1000)

    segments.clear()
    update_score()


def game_frame():
    global score

    move_segments()
    move_head()

    if head.distance(food) < STEP:
        food.goto(random_grid_position())
        add_segment()
        score += 10
        update_score()

    if hit_wall() or hit_body():
        reset_game()

    screen.update()
    screen.ontimer(game_frame, DELAY_MS)


screen.listen()
screen.onkeypress(go_up, "Up")
screen.onkeypress(go_down, "Down")
screen.onkeypress(go_left, "Left")
screen.onkeypress(go_right, "Right")

update_score()
game_frame()
screen.mainloop()

Save the file and run it with python snake_game.py. Use the arrow keys to start moving.

Ways to Improve the Game

  • Decrease DELAY_MS as the score increases.
  • Prevent food from appearing on a body segment.
  • Add a start screen and a game-over message.
  • Save the high score to a text or JSON file.
  • Add obstacles, levels, or special food.
  • Record errors and sessions with Python logging.
  • Move the game state into classes before expanding the project.

Common Problems

The Turtle window opens and closes immediately

Make sure the program ends with screen.mainloop(). It keeps the graphical event loop running until the window is closed.

Keyboard controls do not respond

Call screen.listen() after creating the window, then click the game window once so it has keyboard focus.

The snake moves through the food

Keep both objects aligned to the same grid and use a collision distance close to the grid size.

The snake can reverse into itself

Check the current direction before accepting the opposite direction, as the four input functions do.

Frequently Asked Questions

Do I need to install Turtle?

It is part of Python’s standard library, although some Linux distributions require the Tk interface package for graphical windows.

Can I add images instead of squares?

Yes. Turtle can register compatible image shapes, but simple built-in shapes keep the first version portable.

Why use ontimer() instead of while True?

A scheduled frame function cooperates with Turtle’s event loop, allowing keyboard and window events to remain responsive.

Can this game run in a browser?

Standard Turtle is designed for a desktop graphical environment. A browser version normally requires a different runtime or a web-focused library.

Conclusion

You now have a complete Snake game that uses only Python’s standard library. More importantly, you have practiced reusable programming skills: event handlers, state, lists, functions, coordinate calculations, collision checks, and scheduled updates.

Experiment with one improvement at a time. Changing speed, colors, scoring, food behavior, and level design will teach you more than copying a much larger project all at once. When you need sprites, audio, and more control over the rendering loop, continue with the Pygame version of game development.

Share:

Facebook
WhatsApp
Twitter
LinkedIn

Article content

    Related articles

    Jogo da forca para iniciantes desenvolvido com Python
    Projects
    Foto de perfil de Leandro Hirt da Academify

    Build a Hangman Game in Python

    Build a complete Hangman game in Python with random words, input validation, repeated-letter checks, lives, ASCII art, and replay support.

    Ler mais

    Tempo de leitura: 5 minutos
    10/07/2026
    Quiz interativo no terminal desenvolvido com Python
    Projects
    Foto de perfil de Leandro Hirt da Academify

    Build a Terminal Quiz Game in Python

    Build a terminal quiz game in Python with questions, input validation, scoring, shuffled answers, replay support, JSON loading, and tests.

    Ler mais

    Tempo de leitura: 4 minutos
    10/07/2026
    Jogo de adivinhação de números desenvolvido com Python
    Projects
    Foto de perfil de Leandro Hirt da Academify

    Build a Number Guessing Game in Python

    Build a number guessing game in Python with random numbers, input validation, hints, limited attempts, replay support, and clean functions.

    Ler mais

    Tempo de leitura: 5 minutos
    10/07/2026
    Desenhos para iniciantes usando Turtle em Python
    Projects
    Foto de perfil de Leandro Hirt da Academify

    Python Turtle Drawing: Complete Beginner Guide

    Learn Python Turtle drawing from scratch: move the turtle, draw shapes, use colors, handle keys, and create a complete geometric

    Ler mais

    Tempo de leitura: 5 minutos
    10/07/2026
    Criação de jogos para iniciantes usando Pygame em Python
    Projects
    Foto de perfil de Leandro Hirt da Academify

    Pygame for Beginners: Build Your First Game

    Learn Pygame from scratch: install it, create a window, handle events, move a player, detect collisions, add scoring, and build

    Ler mais

    Tempo de leitura: 6 minutos
    10/07/2026
    Projeto clássico do jogo Pong desenvolvido com Python
    Projects
    Foto de perfil de Leandro Hirt da Academify

    Build Your First Pong Game with Python

    Build your first Pong game with Python and the Turtle module: window setup, paddles, ball physics, collision detection, scoreboard, and

    Ler mais

    Tempo de leitura: 7 minutos
    03/06/2026