Game Development 19 min read

Design and Implementation of a Snake Game Using Python and Pygame

This article presents a comprehensive overview of a Snake game project built with Python and Pygame, detailing game rules, overall design, required libraries, core functions such as food generation, movement, collision detection, mode handling, and includes the complete source code for both normal and wall‑through modes.

Python Programming Learning Circle
Python Programming Learning Circle
Python Programming Learning Circle
Design and Implementation of a Snake Game Using Python and Pygame

The article introduces a classic Snake game, explaining that the player controls the snake with the arrow keys to eat food, grow in length, and avoid colliding with walls or its own body in normal mode, while a wall‑through mode allows the snake to pass through screen edges.

The overall design is illustrated with a framework diagram, showing the separation of initialization, game logic, rendering, and input handling components.

The project is implemented in Python, a cross‑platform, object‑oriented language, and relies on several libraries: pygame for graphics and sound, random for generating food positions, time for delays, and sys for exiting the program.

Game design and implementation are described in detail: a Position class stores coordinates, the snake head and body are managed as a list, and food objects are created with random colors and positions. An initial interface presents three buttons—"Normal Mode", "Wall‑Through Mode", and "Exit"—allowing the player to choose a game mode.

The main functions are analyzed: new_food() generates a new food item avoiding the snake head; start_game() runs the normal mode loop, handling input, updating the snake, checking collisions, and rendering the score; die_snake() determines death in normal mode; through_snake() and start_kgame() implement the wall‑through mode with similar logic but allowing the snake to reappear on the opposite side; show_end() displays the game‑over screen with the final score; button() manages button rendering and click actions; and into_game() drives the start menu.

The runtime module initializes pygame , sets the window size to 960×600, loads background images and music, defines color constants, and starts the main loop by calling into_game() .

Testing screenshots demonstrate the initial selection screen, normal mode gameplay, wall‑through mode gameplay, and the game‑over screen, confirming that both modes function as intended.

Finally, the complete source code of the Snake game is provided below:

import sys
import time
import pygame
from random import *
# Position class, through its constructor, sets x and y
class Position(object):
    def __init__(self, x, y):
        self.x = x
        self.y = y
# Generate random food
def new_food(head):
    while True:
        new_food = Position(randint(0, 48) * 20, randint(0, 29) * 20)
        # Check if the new food coincides with the snake head; if so, regenerate
        if new_food.x != head.x and new_food.y != head.y:
            break
        else:
            continue
    return new_food
# Draw a circle (food or snake segment) in the window
def rect(color, position):
    pygame.draw.circle(window, color, (position.x, position.y), 10)
# Exit the game
def exit_end():
    pygame.quit()
    quit()
# Show the end screen with the final score
def show_end():
    # Design window
    small_window = pygame.display.set_mode((960, 600))
    init_background = pygame.image.load("image/init_bgimg.jpg")
    small_window.blit(init_background, (0, 0))
    pygame.display.set_caption("贪吃蛇大冒险")
    font = pygame.font.SysFont("simHei", 40)
    fontsurf = font.render('游戏结束! 你的得分为: %s' % score, False, black)
    small_window.blit(fontsurf, (250, 200))
    pygame.display.update()
    time.sleep(2)
    pygame.quit()
    sys.exit()
# Normal mode death detection
def die_snake(head, snake_body):
    die_flag = False
    for body in snake_body[1:]:
        if head.x == body.x and head.y == body.y:
            die_flag = True
    if head.x < 0 or head.x > 960 or head.y < 0 or head.y > 600 or die_flag:
        pygame.mixer.music.stop()
        show_end()
# Main loop for normal mode
def start_game():
    global score, color
    color = (randint(10, 255), randint(10, 255), randint(10, 255))
    run_direction = "right"
    run = run_direction
    head = Position(160, 160)
    snake_body = [Position(head.x, head.y + 20), Position(head.x, head.y + 40), Position(head.x, head.y + 60)]
    food = Position(300, 300)
    while True:
        window.blit(background, (0, 0))
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                show_end()
            elif event.type == pygame.KEYDOWN:
                if event.key == pygame.K_UP:
                    run_direction = "up"
                elif event.key == pygame.K_RIGHT:
                    run_direction = "right"
                elif event.key == pygame.K_LEFT:
                    run_direction = "left"
                elif event.key == pygame.K_DOWN:
                    run_direction = "down"
        rect(color, food)
        rect(black, head)
        for pos in snake_body:
            rect(white, pos)
        if run == "up" and not run_direction == "down":
            run = run_direction
        elif run == "down" and not run_direction == "up":
            run = run_direction
        elif run == "left" and not run_direction == "right":
            run = run_direction
        elif run == "right" and not run_direction == "left":
            run = run_direction
        snake_body.insert(0, Position(head.x, head.y))
        if run == "up":
            head.y -= 20
        elif run == "down":
            head.y += 20
        elif run == "left":
            head.x -= 20
        elif run == "right":
            head.x += 20
        die_snake(head, snake_body)
        if head.x == food.x and head.y == food.y:
            score += 1
            food = new_food(head)
            color = (randint(10, 255), randint(10, 255), randint(10, 255))
        else:
            snake_body.pop()
        font = pygame.font.SysFont("simHei", 25)
        mode_title = font.render('正常模式', False, grey)
        socre_title = font.render('得分: %s' % score, False, grey)
        window.blit(mode_title, (50, 30))
        window.blit(socre_title, (50, 65))
        pygame.display.update()
        clock.tick(8)
# Wall‑through mode death detection
def through_snake(head, snake_body):
    die_flag = False
    for body in snake_body[1:]:
        if head.x == body.x and head.y == body.y:
            die_flag = True
    if die_flag:
        pygame.mixer.music.stop()
        show_end()
    else:
        if head.x < 0:
            head.x = 960
        if head.x > 960:
            head.x = 0
        if head.y < 0:
            head.y = 600
        if head.y > 600:
            head.y = 0
# Main loop for wall‑through mode
def start_kgame():
    global score, color
    color = (randint(10, 255), randint(10, 255), randint(10, 255))
    run_direction = "up"
    run = run_direction
    head = Position(160, 160)
    snake_body = [Position(head.x, head.y + 20), Position(head.x, head.y + 40), Position(head.x, head.y + 60)]
    food = Position(300, 300)
    while True:
        window.blit(background, (0, 0))
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                show_end()
            elif event.type == pygame.KEYDOWN:
                if event.key == pygame.K_UP:
                    run_direction = "up"
                elif event.key == pygame.K_RIGHT:
                    run_direction = "right"
                elif event.key == pygame.K_LEFT:
                    run_direction = "left"
                elif event.key == pygame.K_DOWN:
                    run_direction = "down"
        rect(color, food)
        rect(black, head)
        for pos in snake_body:
            rect(white, pos)
        if run == "up" and not run_direction == "down":
            run = run_direction
        elif run == "down" and not run_direction == "up":
            run = run_direction
        elif run == "left" and not run_direction == "right":
            run = run_direction
        elif run == "right" and not run_direction == "left":
            run = run_direction
        snake_body.insert(0, Position(head.x, head.y))
        if run == "up":
            head.y -= 20
        elif run == "down":
            head.y += 20
        elif run == "left":
            head.x -= 20
        elif run == "right":
            head.x += 20
        through_snake(head, snake_body)
        if head.x == food.x and head.y == food.y:
            score += 1
            food = new_food(head)
            color = (randint(10, 255), randint(10, 255), randint(10, 255))
        else:
            snake_body.pop()
        font = pygame.font.SysFont("simHei", 25)
        mode_title = font.render('穿墙模式', False, grey)
        socre_title = font.render('得分: %s' % score, False, grey)
        window.blit(mode_title, (50, 30))
        window.blit(socre_title, (50, 65))
        pygame.display.update()
        clock.tick(8)
# Button handling function
def button(msg, x, y, w, h, ic, ac, action=None):
    mouse = pygame.mouse.get_pos()
    click = pygame.mouse.get_pressed()
    if x + w > mouse[0] > x and y + h > mouse[1] > y:
        pygame.draw.rect(window, ac, (x, y, w, h))
        if click[0] == 1 and action != None:
            action()
    else:
        pygame.draw.rect(window, ic, (x, y, w, h))
    font = pygame.font.SysFont('simHei', 20)
    smallfont = font.render(msg, True, white)
    smallrect = smallfont.get_rect()
    smallrect.center = ((x + (w / 2)), (y + (h / 2)))
    window.blit(smallfont, smallrect)
# Initial game interface
def into_game():
    into = True
    while into:
        window.blit(init_background, (0, 0))
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                exit_end()
        font = pygame.font.SysFont("simHei", 50)
        fontsurf = font.render('欢迎来到贪吃蛇大冒险!', True, black)
        fontrect = fontsurf.get_rect()
        fontrect.center = ((width / 2), 200)
        window.blit(fontsurf, fontrect)
        button("正常模式", 370, 370, 200, 40, blue, brightred, start_game)
        button("可穿墙模式", 370, 420, 200, 40, violte, brightred, start_kgame)
        button("退出", 370, 470, 200, 40, red, brightred, exit_end)
        pygame.display.update()
        clock.tick(15)
if __name__ == '__main__':
    white = (255, 255, 255)
    red = (200, 0, 0)
    green = (0, 128, 0)
    blue = (0, 202, 254)
    violte = (194, 8, 234)
    brightred = (255, 0, 0)
    brightgreen = (0, 255, 0)
    black = (0, 0, 0)
    grey = (129, 131, 129)
    score = 0
    width = 960
    height = 600
    window = pygame.display.set_mode((width, height))
    pygame.display.set_caption("贪吃蛇大冒险")
    init_background = pygame.image.load("image/init_bgimg.jpg")
    background = pygame.image.load("image/bgimg.jpg")
    pygame.mixer.init()
    pygame.mixer.music.load("background.mp3")
    pygame.mixer.music.play(-1)
    clock = pygame.time.Clock()
    pygame.init()
    into_game()
Pythongame developmentTutorialSnake GamePygame
Python Programming Learning Circle
Written by

Python Programming Learning Circle

A global community of Chinese Python developers offering technical articles, columns, original video tutorials, and problem sets. Topics include web full‑stack development, web scraping, data analysis, natural language processing, image processing, machine learning, automated testing, DevOps automation, and big data.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.