Creating a Python Snake Game: Comprehensive Guide
The Snake game is a classic and timeless game that serves as an excellent project for anyone looking to enhance their Python programming skills. In this guide, we'll explore multiple methods to create a Snake game using different Python libraries: tkinter, turtle, and pygame. Each approach offers unique features and complexities, allowing you to choose the one that best fits your preferences and skill level.
Table of Contents
- Creating a Snake Game with Tkinter
- Creating a Snake Game with Turtle
- Creating a Snake Game with Pygame
- Enhancements and Features
- Conclusion
1. Creating a Snake Game with tkinter
tkinter is Python's standard GUI library, making it a convenient choice for creating simple games. Below is a step-by-step guide to building a Snake game using tkinter.
a. Setting Up the Environment
Before diving into the code, ensure that Python is installed on your system. tkinter comes pre-installed with Python, so no additional installations are necessary.
b. The Complete Code
import tkinter as tk
import random
class SnakeGame:
def __init__(self):
self.window = tk.Tk()
self.window.title("Snake Game")
self.canvas = tk.Canvas(self.window, width=800, height=600, bg='black')
self.canvas.pack()
self.snake = [(200, 200), (220, 200), (240, 200)]
self.direction = 'right'
self.food = self.create_food()
self.score = 0
self.game_over = False
self.draw_snake()
self.draw_food()
self.window.bind('', self.turn_up)
self.window.bind('', self.turn_down)
self.window.bind('', self.turn_left)
self.window.bind('', self.turn_right)
self.update()
self.window.mainloop()
def create_food(self):
return (random.randint(0, 39) * 20, random.randint(0, 29) * 20)
def draw_snake(self):
self.canvas.delete('snake')
for segment in self.snake:
self.canvas.create_rectangle(segment[0], segment[1],
segment[0]+20, segment[1]+20,
fill='green', tag='snake')
def draw_food(self):
self.canvas.create_rectangle(self.food[0], self.food[1],
self.food[0]+20, self.food[1]+20,
fill='red', tag='food')
def turn_up(self, event):
if self.direction != 'down':
self.direction = 'up'
def turn_down(self, event):
if self.direction != 'up':
self.direction = 'down'
def turn_left(self, event):
if self.direction != 'right':
self.direction = 'left'
def turn_right(self, event):
if self.direction != 'left':
self.direction = 'right'
def update(self):
if self.game_over:
self.canvas.create_text(400, 300, text="Game Over",
fill="white", font=('Arial', 30))
return
head_x, head_y = self.snake[-1]
if self.direction == 'up':
new_head = (head_x, head_y - 20)
elif self.direction == 'down':
new_head = (head_x, head_y + 20)
elif self.direction == 'left':
new_head = (head_x - 20, head_y)
elif self.direction == 'right':
new_head = (head_x + 20, head_y)
self.snake.append(new_head)
if self.snake[-1] == self.food:
self.score += 1
self.food = self.create_food()
self.draw_food()
else:
self.snake.pop(0)
# Collision Detection
if (self.snake[-1][0] < 0 or self.snake[-1][0] > 780 or
self.snake[-1][1] < 0 or self.snake[-1][1] > 580 or
self.snake[-1] in self.snake[:-1]):
self.game_over = True
self.draw_snake()
self.window.after(100, self.update)
def run(self):
self.window.mainloop()
if __name__ == "__main__":
game = SnakeGame()
game.run()
c. Understanding the Code
The above script initializes a tkinter window and sets up the game elements, including the snake and food. Key aspects include:
-
Snake Initialization: The snake is represented as a list of tuples, each representing a segment's position.
-
Food Creation: Food is randomly placed on the canvas using the
create_foodmethod. -
Movement: Key bindings handle direction changes, ensuring the snake cannot reverse directly.
-
Game Loop: The
updatemethod moves the snake, checks for collisions, and updates the canvas accordingly.
d. Running the Game
- Save the script as
snake_tkinter.py. - Open a terminal and navigate to the script's directory.
- Run the game using the command:
python snake_tkinter.py
2. Creating a Snake Game with turtle
The turtle library is another built-in Python module that allows for unique and visually appealing graphics. Here's how to create a Snake game using turtle.
a. Setting Up the Environment
The turtle library is pre-installed with Python. Ensure you have Python installed to proceed.
b. The Complete Code
import turtle
import time
import random
delay = 0.1
score = 0
high_score = 0
# Set up the screen
screen = turtle.Screen()
screen.title("Snake Game")
screen.bgcolor("blue")
screen.setup(width=600, height=600)
screen.tracer(0) # Turns off the screen updates
# Snake head
head = turtle.Turtle()
head.shape("square")
head.color("white")
head.penup()
head.goto(0, 0)
head.direction = "stop"
# Food
food = turtle.Turtle()
food.shape("circle")
food.color("red")
food.penup()
food.goto(0, 100)
# Score display
score_display = turtle.Turtle()
score_display.speed(0)
score_display.color("white")
score_display.penup()
score_display.hideturtle()
score_display.goto(0, 260)
score_display.write("Score: 0 High Score: 0", align="center", font=("Arial", 24, "normal"))
# Snake segments
segments = []
# Functions
def move_up():
if head.direction != "down":
head.direction = "up"
def move_down():
if head.direction != "up":
head.direction = "down"
def move_left():
if head.direction != "right":
head.direction = "left"
def move_right():
if head.direction != "left":
head.direction = "right"
def move():
if head.direction == "up":
y = head.ycor()
head.sety(y + 20)
if head.direction == "down":
y = head.ycor()
head.sety(y - 20)
if head.direction == "left":
x = head.xcor()
head.setx(x - 20)
if head.direction == "right":
x = head.xcor()
head.setx(x + 20)
# Keyboard bindings
screen.listen()
screen.onkey(move_up, "w")
screen.onkey(move_down, "s")
screen.onkey(move_left, "a")
screen.onkey(move_right, "d")
# Main game loop
while True:
screen.update()
# Check for collision with border
if head.xcor()>290 or head.xcor()<-290 or head.ycor()>290 or head.ycor()<-290:
time.sleep(1)
head.goto(0,0)
head.direction = "stop"
# Hide the segments
for segment in segments:
segment.goto(1000, 1000)
# Clear the segments list
segments.clear()
# Reset the score
score = 0
score_display.clear()
score_display.write("Score: {} High Score: {}".format(score, high_score), align="center", font=("Arial", 24, "normal"))
# Check for collision with food
if head.distance(food) < 20:
# Move the food to a random spot
x = random.randint(-290, 290)
y = random.randint(-290, 290)
food.goto(x, y)
# Add a segment
new_segment = turtle.Turtle()
new_segment.speed(0)
new_segment.shape("square")
new_segment.color("grey")
new_segment.penup()
segments.append(new_segment)
# Increase the score
score += 10
if score > high_score:
high_score = score
score_display.clear()
score_display.write("Score: {} High Score: {}".format(score, high_score), align="center", font=("Arial", 24, "normal"))
# Move the end segments first in reverse order
for index in range(len(segments)-1, 0, -1):
x = segments[index-1].xcor()
y = segments[index-1].ycor()
segments[index].goto(x, y)
# Move segment 0 to where the head is
if len(segments) > 0:
x = head.xcor()
y = head.ycor()
segments[0].goto(x, y)
move()
# Check for head collision with the body segments
for segment in segments:
if segment.distance(head) < 20:
time.sleep(1)
head.goto(0,0)
head.direction = "stop"
# Hide the segments
for segment in segments:
segment.goto(1000, 1000)
segments.clear()
score = 0
score_display.clear()
score_display.write("Score: {} High Score: {}".format(score, high_score), align="center", font=("Arial", 24, "normal"))
time.sleep(delay)
c. Understanding the Code
This implementation leverages the turtle module to create a visually appealing Snake game. Key components include:
- Screen Setup: Initializes the game window with specified dimensions and background color.
- Snake and Food: The snake head and food are represented as
Turtleobjects with specific shapes and colors. - Score Management: Displays the current score and high score using a dedicated
Turtleobject. - Movement and Controls: Functions handle the direction changes based on user input, ensuring the snake moves smoothly.
- Collision Detection: Checks for collisions with the borders and the snake's own body, resetting the game as needed.
- Game Loop: Continuously updates the game state, including movement, collision checks, and score updates.
d. Running the Game
- Save the script as
snake_turtle.py. - Open a terminal and navigate to the script's directory.
- Run the game using the command:
python snake_turtle.py - Control the snake using the W (up), A (left), S (down), and D (right) keys.
3. Creating a Snake Game with pygame
pygame is a powerful library for creating games in Python, offering extensive functionalities for graphics, sound, and input handling. Below are multiple implementations of the Snake game using pygame, each building upon the previous to enhance features and complexity.
a. Basic Snake Game with Pygame
This implementation provides a foundational Snake game with essential features like movement, food consumption, and collision detection.
import pygame
import random
pygame.init()
# Window dimensions
window_width = 600
window_height = 400
window = pygame.display.set_mode((window_width, window_height))
pygame.display.set_caption("Snake Game")
# Colors
black = (0, 0, 0)
white = (255, 255, 255)
red = (255, 0, 0)
green = (0, 255, 0)
# Snake properties
snake_size = 10
snake_speed = 15
# Clock
clock = pygame.time.Clock()
# Fonts
font_style = pygame.font.SysFont(None, 30)
score_font = pygame.font.SysFont(None, 35)
def display_score(score):
value = score_font.render("Score: " + str(score), True, white)
window.blit(value, [0, 0])
def draw_snake(snake_size, snake_list):
for x in snake_list:
pygame.draw.rect(window, green, [x[0], x[1], snake_size, snake_size])
def game_loop():
game_over = False
game_close = False
x = window_width / 2
y = window_height / 2
x_change = 0
y_change = 0
snake_list = []
length_of_snake = 1
food_x = round(random.randrange(0, window_width - snake_size) / 10.0) * 10.0
food_y = round(random.randrange(0, window_height - snake_size) / 10.0) * 10.0
score = 0
while not game_over:
while game_close:
window.fill(black)
message = font_style.render("You Lost! Press C-Play Again or Q-Quit", True, red)
window.blit(message, [window_width / 6, window_height / 3])
display_score(score)
pygame.display.update()
for event in pygame.event.get():
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_q:
game_over = True
game_close = False
if event.key == pygame.K_c:
game_loop()
for event in pygame.event.get():
if event.type == pygame.QUIT:
game_over = True
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
x_change = -snake_size
y_change = 0
elif event.key == pygame.K_RIGHT:
x_change = snake_size
y_change = 0
elif event.key == pygame.K_UP:
y_change = -snake_size
x_change = 0
elif event.key == pygame.K_DOWN:
y_change = snake_size
x_change = 0
# Boundary conditions
if x >= window_width or x < 0 or y >= window_height or y < 0:
game_close = True
x += x_change
y += y_change
window.fill(black)
pygame.draw.rect(window, red, [food_x, food_y, snake_size, snake_size])
snake_head = []
snake_head.append(x)
snake_head.append(y)
snake_list.append(snake_head)
if len(snake_list) > length_of_snake:
del snake_list[0]
# Self-collision
for segment in snake_list[:-1]:
if segment == snake_head:
game_close = True
draw_snake(snake_size, snake_list)
display_score(score)
pygame.display.update()
# Food collision
if x == food_x and y == food_y:
food_x = round(random.randrange(0, window_width - snake_size) / 10.0) * 10.0
food_y = round(random.randrange(0, window_height - snake_size) / 10.0) * 10.0
length_of_snake += 1
score += 1
clock.tick(snake_speed)
pygame.quit()
quit()
game_loop()
b. Enhanced Snake Game with Pygame
This enhanced version incorporates additional features such as scorekeeping, adjustable speed, and improved graphics.
import pygame
import time
import random
pygame.init()
# Window dimensions
window_x = 720
window_y = 480
window = pygame.display.set_mode((window_x, window_y))
pygame.display.set_caption("Snake Game")
# Colors
black = pygame.Color(0, 0, 0)
white = pygame.Color(255, 255, 255)
red = pygame.Color(255, 0, 0)
green = pygame.Color(0, 255, 0)
blue = pygame.Color(0, 0, 255)
# FPS controller
fps = pygame.time.Clock()
# Snake properties
snake_position = [100, 50]
snake_body = [[100, 50], [90, 50], [80, 50], [70, 50]]
fruit_position = [random.randrange(1, (window_x//10)) * 10, random.randrange(1, (window_y//10)) * 10]
fruit_spawn = True
# Direction variables
direction = 'RIGHT'
change_to = direction
# Score
score = 0
# Font
def show_score(choice, color, font, size):
score_font = pygame.font.SysFont(font, size)
score_surface = score_font.render('Score : ' + str(score), True, color)
score_rect = score_surface.get_rect()
if choice == 1:
score_rect.midtop = (window_x / 10, 15)
else:
score_rect.midtop = (window_x / 2, window_y / 1.25)
window.blit(score_surface, score_rect)
# Game Over
def game_over_func():
my_font = pygame.font.SysFont('times new roman', 50)
game_over_surface = my_font.render('YOU DIED', True, red)
game_over_rect = game_over_surface.get_rect()
game_over_rect.midtop = (window_x / 2, window_y / 4)
window.blit(game_over_surface, game_over_rect)
show_score(0, red, 'times', 20)
pygame.display.flip()
time.sleep(2)
pygame.quit()
quit()
# Main Logic
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
quit()
# Whenever a key is pressed down
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_UP or event.key == ord('w'):
change_to = 'UP'
if event.key == pygame.K_DOWN or event.key == ord('s'):
change_to = 'DOWN'
if event.key == pygame.K_LEFT or event.key == ord('a'):
change_to = 'LEFT'
if event.key == pygame.K_RIGHT or event.key == ord('d'):
change_to = 'RIGHT'
# Validation of the direction
if change_to == 'UP' and direction != 'DOWN':
direction = 'UP'
if change_to == 'DOWN' and direction != 'UP':
direction = 'DOWN'
if change_to == 'LEFT' and direction != 'RIGHT':
direction = 'LEFT'
if change_to == 'RIGHT' and direction != 'LEFT':
direction = 'RIGHT'
# Moving the snake
if direction == 'UP':
snake_position[1] -= 10
if direction == 'DOWN':
snake_position[1] += 10
if direction == 'LEFT':
snake_position[0] -= 10
if direction == 'RIGHT':
snake_position[0] += 10
# Snake body growing mechanism
snake_body.insert(0, list(snake_position))
if snake_position[0] == fruit_position[0] and snake_position[1] == fruit_position[1]:
score += 1
fruit_spawn = False
else:
snake_body.pop()
if not fruit_spawn:
fruit_position = [random.randrange(1, (window_x//10)) * 10, random.randrange(1, (window_y//10)) * 10]
fruit_spawn = True
# Background
window.fill(black)
# Draw fruit
pygame.draw.rect(window, green, pygame.Rect(fruit_position[0], fruit_position[1], 10, 10))
# Draw snake
for pos in snake_body:
pygame.draw.rect(window, white, pygame.Rect(pos[0], pos[1], 10, 10))
# Game Over conditions
if snake_position[0] < 0 or snake_position[0] > window_x-10:
game_over_func()
if snake_position[1] < 0 or snake_position[1] > window_y-10:
game_over_func()
# Self collision
for block in snake_body[1:]:
if snake_position[0] == block[0] and snake_position[1] == block[1]:
game_over_func()
show_score(1, white, 'consolas', 20)
pygame.display.update()
fps.tick(snake_speed)
c. Advanced Snake Game with Pygame
This advanced version includes additional features such as levels, different speeds, and more sophisticated graphics to enhance gameplay.
import pygame
import time
import random
pygame.init()
# Initialize display
window_x = 800
window_y = 600
pygame.display.set_caption('Advanced Snake Game')
window = pygame.display.set_mode((window_x, window_y))
# Colors
black = pygame.Color(0, 0, 0)
white = pygame.Color(255, 255, 255)
red = pygame.Color(255, 0, 0)
green = pygame.Color(0, 255, 0)
blue = pygame.Color(0, 0, 255)
grey = pygame.Color(128, 128, 128)
# FPS (frames per second) controller
fps = pygame.time.Clock()
# Snake properties
snake_position = [100, 50]
snake_body = [[100, 50], [90, 50], [80, 50], [70, 50]]
fruit_position = [random.randrange(1, (window_x//10)) * 10, random.randrange(1, (window_y//10)) * 10]
fruit_spawn = True
direction = 'RIGHT'
change_to = direction
# Score
score = 0
# Level
level = 1
speed = 15
# Fonts
font_style = pygame.font.SysFont("bahnschrift", 25)
score_font = pygame.font.SysFont("comicsansms", 35)
def show_score(choice, color, font, size):
score_font_obj = pygame.font.SysFont(font, size)
score_surface = score_font_obj.render('Score : ' + str(score), True, color)
score_rect = score_surface.get_rect()
if choice == 1:
score_rect.midtop = (window_x / 10, 15)
else:
score_rect.midtop = (window_x / 2, window_y / 1.25)
window.blit(score_surface, score_rect)
def draw_snake(snake_block, snake_list):
for x in snake_list:
pygame.draw.rect(window, green, pygame.Rect(x[0], x[1], snake_block, snake_block))
def message(msg, color):
mesg = font_style.render(msg, True, color)
window.blit(mesg, [window_x / 6, window_y / 3])
def gameLoop():
global score, level, speed
game_over = False
game_close = False
x1 = window_x / 2
y1 = window_y / 2
x1_change = 0
y1_change = 0
snake_List = []
Length_of_snake = 1
foodx = round(random.randrange(0, window_x - 10) / 10.0) * 10.0
foody = round(random.randrange(0, window_y - 10) / 10.0) * 10.0
while not game_over:
while game_close:
window.fill(black)
message("You Lost! Press C-Play Again or Q-Quit", red)
show_score(0, red, "comicsansms", 20)
pygame.display.update()
for event in pygame.event.get():
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_q:
game_over = True
game_close = False
if event.key == pygame.K_c:
score = 0
level = 1
speed = 15
gameLoop()
for event in pygame.event.get():
if event.type == pygame.QUIT:
game_over = True
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT or event.key == ord('a'):
change_to = 'LEFT'
elif event.key == pygame.K_RIGHT or event.key == ord('d'):
change_to = 'RIGHT'
elif event.key == pygame.K_UP or event.key == ord('w'):
change_to = 'UP'
elif event.key == pygame.K_DOWN or event.key == ord('s'):
change_to = 'DOWN'
elif event.key == pygame.K_ESCAPE:
game_over = True
# Validation of direction
if change_to == 'UP' and direction != 'DOWN':
direction = 'UP'
if change_to == 'DOWN' and direction != 'UP':
direction = 'DOWN'
if change_to == 'LEFT' and direction != 'RIGHT':
direction = 'LEFT'
if change_to == 'RIGHT' and direction != 'LEFT':
direction = 'RIGHT'
# Moving the snake
if direction == 'UP':
y1 -= 10
if direction == 'DOWN':
y1 += 10
if direction == 'LEFT':
x1 -= 10
if direction == 'RIGHT':
x1 += 10
# Snake body growing
snake_Head = []
snake_Head.append(x1)
snake_Head.append(y1)
snake_List.append(snake_Head)
if len(snake_List) > Length_of_snake:
del snake_List[0]
# Collision with self
for x in snake_List[:-1]:
if x == snake_Head:
game_close = True
# Boundary collision
if x1 >= window_x or x1 < 0 or y1 >= window_y or y1 < 0:
game_close = True
window.fill(black)
pygame.draw.rect(window, red, pygame.Rect(foodx, foody, 10, 10))
draw_snake(10, snake_List)
show_score(1, white, "comicsansms", 20)
pygame.display.update()
# Collision with food
if x1 == foodx and y1 == foody:
foodx = round(random.randrange(0, window_x - 10) / 10.0) * 10.0
foody = round(random.randrange(0, window_y - 10) / 10.0) * 10.0
Length_of_snake += 1
score += 1
if score % 5 == 0:
level += 1
speed += 5
fps.tick(speed)
pygame.quit()
quit()
gameLoop()
d. Running the Game
- Ensure
pygameis installed. If not, install it using:pip install pygame - Save the desired implementation as
snake_pygame.py. - Open a terminal and navigate to the script's directory.
- Run the game using the command:
python snake_pygame.py - Control the snake using the arrow keys or W (up), A (left), S (down), and D (right) keys.
4. Enhancements and Features
Once you've mastered the basic Snake game, consider adding the following features to enhance gameplay and complexity:
a. Sound Effects
Add sound effects for actions like eating food or game over events to make the game more engaging.
# Initialize mixer
pygame.mixer.init()
# Load sounds
eat_sound = pygame.mixer.Sound('eat.wav')
game_over_sound = pygame.mixer.Sound('game_over.wav')
# Play sound on eating food
if x1 == foodx and y1 == foody:
pygame.mixer.Sound.play(eat_sound)
# Rest of the code...
# Play sound on game over
if collision_detected:
pygame.mixer.Sound.play(game_over_sound)
game_close = True
b. Increasing Difficulty Levels
Implementing levels that increase in difficulty can make the game more challenging. Increase the snake's speed or introduce obstacles as the player progresses.
c. Obstacles
Add obstacles within the game window that the snake must avoid. Collision with these obstacles should result in a game over.
# Define obstacle positions
obstacles = [
pygame.Rect(200, 200, 10, 10),
pygame.Rect(300, 300, 10, 10),
# Add more obstacles as needed
]
# Draw obstacles
for obs in obstacles:
pygame.draw.rect(window, grey, obs)
# Collision with obstacles
for obs in obstacles:
if snake_head_rect.colliderect(obs):
game_close = True
d. High Score Tracking
Persist the high score across game sessions by saving it to a file.
import os
def load_high_score():
if os.path.exists("high_score.txt"):
with open("high_score.txt", "r") as f:
return int(f.read())
return 0
def save_high_score(new_high_score):
with open("high_score.txt", "w") as f:
f.write(str(new_high_score))
# Initialize high score
high_score = load_high_score()
# Update high score
if score > high_score:
high_score = score
save_high_score(high_score)
# Display high score
def show_score(choice, color, font, size):
...
if choice == 1:
score_surface = score_font_obj.render('Score : ' + str(score) + ' High Score: ' + str(high_score), True, color)
...
e. Graphical Enhancements
Improve the game's visuals by adding images, animations, or more intricate designs for the snake and food.
# Load images
snake_img = pygame.image.load('snake.png')
food_img = pygame.image.load('food.png')
# Draw snake with image
for x in snake_list:
window.blit(snake_img, (x[0], x[1]))
# Draw food with image
window.blit(food_img, (foodx, foody))
5. Conclusion
Creating a Snake game in Python is a rewarding project that helps solidify your understanding of programming concepts such as loops, conditionals, data structures, and event handling. By exploring different libraries like tkinter, turtle, and pygame, you can appreciate the versatility of Python in game development.
Start with a basic implementation and gradually introduce more features and complexities as your confidence grows. Happy coding and enjoy your Snake game!
Last updated January 3, 2025