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.
Install pygame
using pip:
pip install pygame
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
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])
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 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
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
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
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)
When the game is over, pygame.quit()
is called to close the game window, and quit()
which quits the game
pygame.quit()
quit()
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()
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.