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.
tkintertkinter 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.
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.
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()
The above script initializes a tkinter window and sets up the game elements, including the snake and food. Key aspects include:
create_food method.
update method moves the snake, checks for collisions, and updates the canvas accordingly.
snake_tkinter.py.python snake_tkinter.pyturtleThe 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.
The turtle library is pre-installed with Python. Ensure you have Python installed to proceed.
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)
This implementation leverages the turtle module to create a visually appealing Snake game. Key components include:
Turtle objects with specific shapes and colors.Turtle object.snake_turtle.py.python snake_turtle.pypygamepygame 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.
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()
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)
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()
pygame is installed. If not, install it using:
pip install pygame
snake_pygame.py.python snake_pygame.pyOnce you've mastered the basic Snake game, consider adding the following features to enhance gameplay and complexity:
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
Implementing levels that increase in difficulty can make the game more challenging. Increase the snake's speed or introduce obstacles as the player progresses.
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
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)
...
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))
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!