paint-brush
Who Doesn't Love the Classic Snake Game? by@ajayvallab
150 reads New Story

Who Doesn't Love the Classic Snake Game?

by Ajay Krishnan PrabhakaranJanuary 15th, 2025
Read on Terminal Reader
Read this story w/o Javascript
tldt arrow

Too Long; Didn't Read

Learn to create a classic Snake game using Python and Pygame. This guide covers setting up the environment, understanding the code, handling user input, and rendering graphics. It's an excellent introduction to game development and fundamental programming concepts. Expand your skills by adding features like score tracking and levels.
featured image - Who Doesn't Love the Classic Snake Game?
Ajay Krishnan Prabhakaran HackerNoon profile picture
0-item
1-item
2-item

Who doesn’t love the classic Snake game. I remember back in 2007 when I first got my mobile phone, I used to spend countless hours playing Snake. Today in this article we will be covering how to build it using Python and pygame a game development library. This would be perfect for anyone who wants to learn python as we will be covering various topics like loops, data structures, if else statements, handling user inputs, while also having fun building a nostalgic game.

Setting Up the Environment

Install pygame using pip:


pip install pygame

Understanding the Code

Initialization

We first import pygame and random modules which we will use to create the GUI and random generation of food for the Snake. We then initialize the game pygame.init(), where we set the specific colors for different components of our window. We then set the dimensions of the window using pygame.display.set_mode() and give it a name using pygame.display.set_caption().


clock = pygame.time.Clock(), initializes a Clock object where we define the size of each block of the snake and also the speed at which the snake moves. This can be set to a low value initially and later increased based on user skill level. Play around with these values to see which one suits you best

import pygame
import random
pygame.init()


white = (255, 255, 255)
yellow = (255, 255, 102)
black = (0, 0, 0)
red = (213, 50, 80)
green = (0, 255, 0)
blue = (50, 153, 213)
display_width = 800
display_height = 600
dis = pygame.display.set_mode((display_width, display_height))
pygame.display.set_caption('Snake Game')
clock = pygame.time.Clock()
sk_block = 10
sk_speed = 15

Game Functions

Drawing the Snake

The our_snake function is responsible for making the snake come to life on the screen. By drawing each part of the snake as a rectangle iteratively using pygame.draw.rect() we render it on the screen and it is called every time the snake moves through the screen

def our_sk(sk_block, sk_list):
    for x in sk_list:
        pygame.draw.rect(dis, black, [x[0], x[1], sk_block, sk_block])

Displaying Messages

To render a message on the screen like ‘Game Over‘ we use pygame.font.SysFont() to create a font object and use render() to create a surface with the text. The message is then displayed on the window at the specified location using blit method

def message(msg, color):
    message_to_display = font_style.render(msg, True, color)
    dis.blit(message_to_display, [display_width / 6, display_height / 3])

The Game Loop

The gameLoop() defines several essential variables like game_over and game_close to False, indicating the game is still active and not over just yet. The snake's initial position is at the center of the screen, by setting x1 and y1 to half the size of the screen. x1_value_change and y1_value_change are set to zero, which we will use to track snake’s movement. The sk_list is where will be storing the different segments of the snake as game progress and length_of_snake is set to 1 initially. The food's position is then randomly displayed on the window with respect to where the snake is and also within the bounds of the window

def gameLoop():
    sk_game_over = False
    sk_game_close = False
    x1 = display_width / 2
    y1 = display_height / 2
    x1_value_change = 0
    y1_value_change = 0
    sk_list = []
    length_of_sk = 1
    sanke_foodx = round(random.randrange(0, display_width - sk_block) / 10.0) * 10.0
    sanke_foody = round(random.randrange(0, display_height - sk_block) / 10.0) * 10.0

Handling User Input

We have two nested while loops. The outer while loop, keeps the game running until the game_over condition is satisfied. Inside this loop, there's another while loop, which handles the scenario when the player loses ( when this happens the display is filled with a blue color and a message prompting the player to press 'Q' to quit or 'C' to play again. The pygame.event.get() handles listening to key strokes ie if player presses 'Q' the game ends by setting game_over to True and if 'C' is pressed, the game restarts by calling gameLoop().

Outside the game_close loop, the code would be listening for other events like arrow key presses. When the player presses left or right arrow x1_value_change is updated to move the snake horizontally, and when up or down arrow is pressed y1_value_change changes to move the snake vertically, controlling the direction in which the snake needs to proceed

    while not sk_game_over:
        while sk_game_close:
            dis.fill(blue)
            message("Oops you lost the game! You can press Q to Quit or press C to Play Again", red)
            pygame.display.update()
            for sk_event in pygame.event.get():
                if sk_event.type == pygame.KEYDOWN:
                    if sk_event.key == pygame.K_q:
                        sk_game_over = True
                        sk_game_close = False
                    if sk_event.key == pygame.K_c:
                        gameLoop()
        for sk_event in pygame.event.get():
            if sk_event.type == pygame.QUIT:
                sk_game_over = True
            if sk_event.type == pygame.KEYDOWN:
                if sk_event.key == pygame.K_LEFT:
                    x1_value_change = -sk_block
                    y1_value_change = 0
                elif sk_event.key == pygame.K_RIGHT:
                    x1_value_change = sk_block
                    y1_value_change = 0
                elif sk_event.key == pygame.K_UP:
                    y1_value_change = -sk_block
                    x1_value_change = 0
                elif sk_event.key == pygame.K_DOWN:
                    y1_value_change = sk_block
                    x1_value_change = 0

Updating the Game State

Next we need to handle the movement and collision detection for the snake. The first if statement checks if the snake's head (x1, y1) has collided with the boundaries of the window (display_width and display_height). If it does game_close is set to True, setting the game to a "game over" state. The snake's position is updated by adding x1_value_change and y1_value_change to x1 and y1, which reflects the direction in which the snake is moving. The display is then filled by color blue, and the food is drawn as a green square at positions (foodx, foody).


A new list snake_head, is created to store the current position of the snake's head, which is then appended to sk_list, to represent the entire snake. If the length of sk_list exceeds length_of_snake, the oldest block is removed to maintain the correct length.


The final for loop iterates over the snake's body segments (excluding the head) to check for self-collision. If this happens, ie the snake's head matches any of its body segments positions, game_close is set to True, ending the game

        if x1 >= display_width or x1 < 0 or y1 >= display_height or y1 < 0:
            sk_game_close = True
        x1 += x1_value_change
        y1 += y1_value_change
        dis.fill(blue)
        pygame.draw.rect(dis, green, [sanke_foodx, sanke_foody, sk_block, sk_block])
        sk_head = []
        sk_head.append(x1)
        sk_head.append(y1)
        sk_list.append(sk_head)
        if len(sk_list) > length_of_sk:
            del sk_list[0]
        for x in sk_list[:-1]:
            if x == sk_head:
                sk_game_close = True

Rendering the Game

The function our_snake(snake_block, sk_list) is called to display our snake on the screen using current list of snake segments. The pygame.display.update() refreshes the screen to update any of the changes made during the game loop. The if condition checks if snake's head (x1, y1) match the food's position (foodx, foody). If they do, new random position for the food is generated and snake's length is increased by one. We need clock.tick(snake_speed) to regulate the game's frame rate, making sure gameplay speed is consistent.


        our_sk(sk_block, sk_list)
        pygame.display.update()
        if x1 == sanke_foodx and y1 == sanke_foody:
            sanke_foodx = round(random.randrange(0, display_width - sk_block) / 10.0) * 10.0
            sanke_foody = round(random.randrange(0, display_height - sk_block) / 10.0) * 10.0
            length_of_sk += 1
        clock.tick(sk_speed)

Ending the Game

When the game is over, pygame.quit() is called to close the game window, and quit() which quits the game

    pygame.quit()
    quit()

Complete Code

import pygame
import random
pygame.init()


white = (255, 255, 255)
yellow = (255, 255, 102)
black = (0, 0, 0)
red = (213, 50, 80)
green = (0, 255, 0)
blue = (50, 153, 213)
display_width = 800
display_height = 600
dis = pygame.display.set_mode((display_width, display_height))
pygame.display.set_caption('Snake Game')
clock = pygame.time.Clock()
sk_block = 10
sk_speed = 15
font_style = pygame.font.SysFont(None, 50)
score_font = pygame.font.SysFont(None, 35)

def our_sk(sk_block, sk_list):
    for x in sk_list:
        pygame.draw.rect(dis, black, [x[0], x[1], sk_block, sk_block])

def message(msg, color):
    message_to_display = font_style.render(msg, True, color)
    dis.blit(message_to_display, [display_width / 6, display_height / 3])

def gameLoop():
    sk_game_over = False
    sk_game_close = False
    x1 = display_width / 2
    y1 = display_height / 2
    x1_value_change = 0
    y1_value_change = 0
    sk_list = []
    length_of_sk = 1
    sanke_foodx = round(random.randrange(0, display_width - sk_block) / 10.0) * 10.0
    sanke_foody = round(random.randrange(0, display_height - sk_block) / 10.0) * 10.0
    while not sk_game_over:
        while sk_game_close:
            dis.fill(blue)
            message("Oops you lost the game! You can press Q to Quit or press C to Play Again", red)
            pygame.display.update()
            for sk_event in pygame.event.get():
                if sk_event.type == pygame.KEYDOWN:
                    if sk_event.key == pygame.K_q:
                        sk_game_over = True
                        sk_game_close = False
                    if sk_event.key == pygame.K_c:
                        gameLoop()
        for sk_event in pygame.event.get():
            if sk_event.type == pygame.QUIT:
                sk_game_over = True
            if sk_event.type == pygame.KEYDOWN:
                if sk_event.key == pygame.K_LEFT:
                    x1_value_change = -sk_block
                    y1_value_change = 0
                elif sk_event.key == pygame.K_RIGHT:
                    x1_value_change = sk_block
                    y1_value_change = 0
                elif sk_event.key == pygame.K_UP:
                    y1_value_change = -sk_block
                    x1_value_change = 0
                elif sk_event.key == pygame.K_DOWN:
                    y1_value_change = sk_block
                    x1_value_change = 0
        if x1 >= display_width or x1 < 0 or y1 >= display_height or y1 < 0:
            sk_game_close = True
        x1 += x1_value_change
        y1 += y1_value_change
        dis.fill(blue)
        pygame.draw.rect(dis, green, [sanke_foodx, sanke_foody, sk_block, sk_block])
        sk_head = []
        sk_head.append(x1)
        sk_head.append(y1)
        sk_list.append(sk_head)
        if len(sk_list) > length_of_sk:
            del sk_list[0]
        for x in sk_list[:-1]:
            if x == sk_head:
                sk_game_close = True
        our_sk(sk_block, sk_list)
        pygame.display.update()
        if x1 == sanke_foodx and y1 == sanke_foody:
            sanke_foodx = round(random.randrange(0, display_width - sk_block) / 10.0) * 10.0
            sanke_foody = round(random.randrange(0, display_height - sk_block) / 10.0) * 10.0
            length_of_sk += 1
        clock.tick(sk_speed)
    pygame.quit()
    quit()

gameLoop()


Output

Classic Snake game in Python


Conclusion

We can take this even further by adding score tracking, advanced graphics, different levels with more difficulties like obstacles or increased speed, to keep it exciting. The best way to learn anything is by doing it through fun and play. So I hope this article helped you get excited on the possibilities on what can be achieved through simple python programming and that one day you would build something exciting that would be the next generations greatest game.