This post is completed by 1 user
|
Add to List |
557. How to Build a Snake Game in Python Using Pygame
In this tutorial, we’ll walk through how to build a classic Snake Game in Python using the pygame
library. We’ll start by explaining each component of the game and how they work together to create an engaging, interactive experience.
Overview of the Game
The Snake Game is a well-known game where the player controls a snake that moves around a grid to eat food (in this case, apples). The snake grows longer each time it eats an apple, and the player must avoid colliding with the snake’s own body or the walls.
Key Features:
- Snake Movement: The snake moves automatically in one direction, controlled by the arrow keys.
- Apple: Randomly placed on the screen, and the snake must "eat" the apple by moving over it.
- Collision Detection: The game checks if the snake collides with its body or edges.
- Score and High Score: A score that increments when the snake eats an apple, and a high score stored in a file.
- Speed Control: The player can control the speed of the snake by pressing numeric keys (1 to 5).
Building a classic Snake game in Python is a fun and educational way to learn about game development and object-oriented programming. In this tutorial, we’ll walk you through creating a fully functional Snake game using Pygame, a popular game development library in Python. The game will feature basic elements such as the snake, food (apples), score tracking, and collision detection.
By the end, you’ll understand how to build and run the game, and you’ll have a working Snake game to play and enhance.
Click here to jump to YouTube tutorial video
Table of Contents:
- Introduction to Pygame
- Setting Up the Game
- Understanding the Snake Class
- Creating the Apple Class
- Managing Game State and Score
- Handling Collisions and Game Over
- Running the Game Loop
- Youtube Tutorial Video
- Complete Code
- Conclusion
Setting Up Pygame
First, we need to install the pygame
library, which is a popular module for game development in Python.
import pygame
import random
import os
import json
SCREEN_SIZE = 800
BLOCK_WIDTH = 40
Here, SCREEN_SIZE
is the size of the game window, and BLOCK_WIDTH
represents the size of each segment of the snake and the apple.
Snake Class
The Snake
class handles the snake’s movement, drawing, and growth mechanics. This is one of the core components of our game.
class Snake:
def __init__(self, parent_screen, length=5):
self.length = length
self.parent_screen = parent_screen
self.block = pygame.image.load("resources/block.jpg") # Snake body block image
self.x = [BLOCK_WIDTH] * self.length # Initial X-coordinates of the snake body
self.y = [BLOCK_WIDTH] * self.length # Initial Y-coordinates of the snake body
self.direction = "right" # Snake's initial direction
Explanation of the properties:
- parent_screen: The screen where the snake is drawn.
- length: The initial length of the snake.
- block: The image representing the snake’s body.
- x, y: Lists that store the positions of the snake’s blocks.
- direction: Tracks the snake's current movement direction.
def draw(self):
self.parent_screen.fill((0, 0, 0)) # Clear the screen (black background)
for i in range(self.length):
self.parent_screen.blit(self.block, (self.x[i], self.y[i])) # Draw the snake
- This method is called to render the snake on the screen.
- It clears the previous frame and redraws each segment of the snake using the coordinates stored in
self.x
andself.y
.
Snake Movement
def move_left(self):
if self.direction != 'right':
self.direction = 'left'
def move_right(self):
if self.direction != 'left':
self.direction = 'right'
def move_up(self):
if self.direction != 'down':
self.direction = 'up'
def move_down(self):
if self.direction != 'up':
self.direction = 'down'
These functions ensure the snake can’t reverse direction immediately, which would cause instant death by collision.
Updating Snake Position
The snake moves by shifting the positions of its body parts. The head moves in the current direction, while each body part follows the one before it.
def move(self):
for i in range(self.length - 1, 0, -1): # Shift the body parts forward
self.x[i] = self.x[i - 1]
self.y[i] = self.y[i - 1]
if self.direction == 'right':
self.x[0] += BLOCK_WIDTH
elif self.direction == 'left':
self.x[0] -= BLOCK_WIDTH
elif self.direction == 'up':
self.y[0] -= BLOCK_WIDTH
elif self.direction == 'down':
self.y[0] += BLOCK_WIDTH
# Wrap around the screen (appear on the other side)
if self.x[0] >= SCREEN_SIZE:
self.x[0] = 0
elif self.x[0] < 0:
self.x[0] = SCREEN_SIZE
if self.y[0] >= SCREEN_SIZE:
self.y[0] = 0
elif self.y[0] < 0:
self.y[0] = SCREEN_SIZE
self.draw()
- Purpose: This method updates the snake’s position based on its current direction.
- How it works:
- The snake’s body shifts forward, with each block taking the position of the block ahead of it.
- The head (
self.x[0]
andself.y[0]
) moves in the direction specified byself.direction
. - The method also ensures that the snake wraps around the screen when it reaches the edges.
Apple Class
The Apple
class manages the apple (food) that the snake eats. It randomly positions the apple on the game grid, ensuring it doesn't overlap the snake’s body.
Placing the Apple
class Apple:
class Apple:
def __init__(self, parent_screen):
self.parent_screen = parent_screen
self.apple_img = pygame.image.load("resources/apple.jpg") # Apple image
self.x = BLOCK_WIDTH * 4
self.y = BLOCK_WIDTH * 5
def draw(self):
self.parent_screen.blit(self.apple_img, (self.x, self.y)) # Draw apple
The apple image is loaded, and it’s initially placed at a random position on the grid.
Moving the Apple
Repositions the apple randomly on the grid while ensuring it doesn’t overlap with the snake’s body.
def move(self, snake):
while True:
x = random.randint(0, 19) * BLOCK_WIDTH
y = random.randint(0, 19) * BLOCK_WIDTH
clean = True
for i in range(0, snake.length):
if x == snake.x[i] and y == snake.y[i]:
clean = False
break
if clean:
self.x = x
self.y = y
return
Game Class
The Game
class handles the main game loop, including score tracking, controlling speed, and saving high scores.
Initialization
class Game:
def __init__(self):
pygame.init()
pygame.display.set_caption("Snake Game - PyGame")
self.SCREEN_UPDATE = pygame.USEREVENT
self.timer = 150
pygame.time.set_timer(self.SCREEN_UPDATE, self.timer)
self.surface = pygame.display.set_mode((SCREEN_SIZE, SCREEN_SIZE))
self.snake = Snake(self.surface)
self.apple = Apple(parent_screen=self.surface)
self.score = 0
self.record = 00
self.retrieve_data()
This initializes the game, sets up the window, and retrieves the high score from a file.
Save and Retrieve Data
Saves the current high score to a JSON file and Loads the high score from a file so it can be displayed in-game.
def save_data(self):
data_folder_path = "./resources"
file_name = "data.json"
if not os.path.exists(data_folder_path):
os.makedirs(data_folder_path)
complete_path = os.path.join(data_folder_path, file_name)
data = {'record': self.record}
with open(complete_path, 'w') as file:
json.dump(data, file, indent=4)
def retrieve_data(self):
data_folder_path = os.path.join("./resources", "data.json")
if os.path.exists(data_folder_path):
with open(data_folder_path, 'r') as file:
data = json.load(file)
if data is not None:
self.record = data['record']
Speed Control
The game supports 5 different speed levels, which can be controlled by pressing keys 1-5. Each number corresponds to a different speed, changing the timer interval.
def run(self):
running = True
pause = False
while running:
for event in pygame.event.get():
if event.type == KEYDOWN:
if event.key == K_1:
self.timer = 10
if event.key == K_2:
self.timer = 50
if event.key == K_3:
self.timer = 100
if event.key == K_4:
self.timer = 150
if event.key == K_5:
self.timer = 200
...
elif event.type == self.SCREEN_UPDATE:
if not pause:
self.play()
Scoring System
The game tracks the player’s score and updates the high score (record) whenever a new high score is reached:
def play(self):
self.snake.move()
self.apple.draw()
self.display_score()
if self.snake.x[0] == self.apple.x and self.snake.y[0] == self.apple.y:
self.score += 1
self.snake.increase()
self.apple.move(self.snake)
if self.record < self.score:
self.record = self.score
self.save_data()
Display Score
- Displays the current score and high score on the game screen.
- The method renders the score and record as text using Pygame’s
SysFont
and draws it at the top-left corner of the screen.
def display_score(self):
font = pygame.font.SysFont('arial', 30)
score_text = f"Score: {self.score} Record: {self.record}"
score_render = font.render(score_text, True, (255, 255, 255))
self.surface.blit(score_render, (10, 10))
Handling Collisions and Game Over
Collision detection is crucial in Snake games. If the snake collides with its own body, the game ends.
for i in range(1, self.snake.length):
if self.snake.x[0] == self.snake.x[i] and self.snake.y[0] == self.snake.y[i]:
raise Exception("Collision Occurred")
If a collision is detected, the game throws an exception, signaling the game over.
Game Over
The game ends when the snake collides with its own body. The show_game_over
method displays the final score and prompts the user to restart:
def show_game_over(self):
font = pygame.font.SysFont('arial', 30)
line = font.render(f"Game over! score is {self.score}", True, (255, 255, 255))
self.surface.blit(line, (200, 300))
line1 = font.render(f"Press Enter to Restart", True, (255, 255, 255))
self.surface.blit(line1, (200, 350))
pygame.display.update()
pygame.mixer.music.pause()
Running the Game Loop
Finally, the run
method contains the game loop that keeps the game running until the player quits or the snake collides with itself.
def run(self):
running = True
pause = False
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_RETURN:
pause = False
if not pause:
try:
self.play()
except Exception:
self.show_game_over()
pause = True
pygame.display.update()
- Manages the overall game loop and listens for user input (such as pausing and restarting the game).
- It continuously checks for events like quitting the game or pressing keys. If the game is paused, the loop halts until the player resumes by pressing the Enter key. The game updates the screen in each iteration of the loop using
pygame.display.update()
.
Complete Code
- GitHub
Conclusion
You now have a working Snake game built using Python and Pygame! This project covered the essentials of game development, including object-oriented design, rendering graphics, handling user input, managing game state, and collision detection.
Feel free to expand this game by adding more features like sound effects, levels, or different types of food. Have fun coding!