Remember that snake game from back in the day. Today, we're diving into the world of Python programming to create our very own version of this iconic game.
What is the Snake Game and How it Works
The snake game is a simple yet addictive game where the player controls a snake that moves around a bordered area, gobbling up food (often represented as dots or other objects) to grow longer. The main challenge is to avoid collisions with the walls of the playing area or with the snake's own body. As the snake consumes more food, it grows longer, making it progressively harder to navigate without crashing into something.
Here's a basic rundown of how the game typically works:
Initialization: The game starts with a snake consisting of a single segment and randomly placed food within the play area.
Movement: The snake moves continuously in the direction specified by the player (up, down, left, or right).
Eating: When the snake's head collides with a food item, it "eats" the food, grows longer, and scores points.
Collision Detection: The game checks for collisions between the snake's head and the walls of the play area or its own body. If a collision occurs, the game ends.
Game Over: When the snake collides with a wall or itself, the game ends, and the player's score is displayed.
Project Specifications
Now, let's outline the specifications for building our snake game in Python:
Graphical Interface: We'll use a graphical interface library such as Pygame or Tkinter to create the game window and handle user input.
Snake Movement: Implement logic to control the snake's movement based on user input.
Food Generation: Randomly generate food within the play area for the snake to consume.
Collision Detection: Detect collisions between the snake's head and the walls or its own body.
Score Tracking: Keep track of the player's score based on the number of food items eaten.
Game Over: Display a game over screen when the snake collides with a wall or itself.
Unfortunately, we are going to make use of a blocks for simpliity.
With these specifications in mind, we're ready to dive into coding our very own snake game in Python! Let's get started!
Game Mechanics Explained
Array of Player Information
We'll maintain an array to store information about each segment of the snake's body. Each element in this array will represent a segment and contain the following information:
- Segment Location: The coordinates (x, y) of the segment on the game grid.
- Direction: The direction in which the segment should move next.
Segment Movement and Direction
Notice that in snake games different segments of the snake is moving in different directions, in this implementation, each segment can move independently based on the direction assigned to it. This creates a segmented movement effect where different parts of the snake follow the movements of the preceding segments. The animation above clearly depicts this with the use of arrows.
Adding New Segments
When the snake eats food and grows longer, a new segment is added to the end of the snake. The direction of this new segment is set to match the direction of the last segment in the snake's body. This ensures that the new segment follows the movement direction of the rest of the snake.
Trail-like Movement
As the game progresses and the snake moves, each segment follows the direction of the segment before it, creating a trail-like movement effect. This trail effect mimics the behavior of a real snake, where each part of its body follows the movements of the head.
Direction Assignment
With each game tick, the direction assigned to each segment of the snake's body moves down the snake, ensuring that each segment follows the movement of the segment before it. This sequential assignment of directions creates the illusion of a continuous, slithering motion.
Code Explained
import pygame
import sys
import random
# Initialize pygame
pygame.init()
# Constants
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
# Variables
block_size = 50
num_blocks_x = 16
num_blocks_y = 12
# Calculate window width and height
SCREEN_WIDTH = block_size * num_blocks_x
SCREEN_HEIGHT = block_size * num_blocks_y
# Clock speed
clock_speed = 10 # frames per second
def draw_grid(screen):
for x in range(0, SCREEN_WIDTH, block_size):
pygame.draw.line(screen, WHITE, (x, 0), (x, SCREEN_HEIGHT))
for y in range(0, SCREEN_HEIGHT, block_size):
pygame.draw.line(screen, WHITE, (0, y), (SCREEN_WIDTH, y))
def check_border_collision(player_list):
for player in player_list:
if player[0] < 0 or player[0] >= num_blocks_x or player[1] < 0 or player[1] >= num_blocks_y:
return True
return False
def handle_game_object_collision(game_objects):
# Collision detection for player colliding with itself
player_positions = [(pos[0], pos[1]) for pos in game_objects["player"]]
for pos in player_positions[1:]:
if player_positions[0] == pos:
return True
# Check for collision between player and fruits
for fruit in ["fruit_1", "fruit_2"]:
if game_objects["player"][0][:2] == game_objects[fruit]:
# If player touches the fruit, generate a new random position for the fruit
game_objects[fruit] = [random.randint(0, num_blocks_x - 1), random.randint(0, num_blocks_y - 1)]
# Add a new list to player's list with the same direction as the last element
last_direction = game_objects["player"][-1][2]
new_player_pos = list(game_objects["player"][-1][:2])
if last_direction == 0:
# Move down
new_player_pos[1] += 1
elif last_direction == 1:
# Move up
new_player_pos[1] -= 1
elif last_direction == 2:
# Move right
new_player_pos[0] += 1
elif last_direction == 3:
# Move left
new_player_pos[0] -= 1
game_objects["player"].append(new_player_pos + [last_direction])
return False
def check_input_direction():
direction = None # Reset direction to None at the beginning of each iteration
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_w:
direction = 0 # Up
elif event.key == pygame.K_s:
direction = 1 # Down
elif event.key == pygame.K_a:
direction = 2 # Left
elif event.key == pygame.K_d:
direction = 3 # Right
elif event.key == pygame.K_ESCAPE:
direction = 4 # Right
return direction
def handle_snake_rotation(game_objects):
for i in reversed(range(1, len(game_objects["player"]))):
game_objects["player"][i][2] = game_objects["player"][i - 1][2]
def main():
# Set up the display
screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
pygame.display.set_caption("Pygame Grid")
# Clock object to control frame rate
clock = pygame.time.Clock()
# Font for displaying text
font = pygame.font.SysFont(None, 30)
# Dictionary to store game objects
game_objects = {
"player": [[1, 1, None]], # Initial position of player at (1, 1) with no direction
"fruit_1": [5, 5], # Initial position of fruit_1 at (5, 5)
"fruit_2": [10, 10] # Initial position of fruit_2 at (10, 10)
}
running = True
end_game = False
while running:
direction = check_input_direction()
if direction == 4:
break
# Set direction of the first element of player if direction is not None
if direction is not None:
game_objects["player"][0][2] = direction
# Move player based on direction
for player in game_objects["player"]:
if end_game:
break
dir_player = player[2]
if dir_player == 0:
# Move player up
player[1] -= 1
elif dir_player == 1:
# Move player down
player[1] += 1
elif dir_player == 2:
# Move player left
player[0] -= 1
elif dir_player == 3:
# Move player right
player[0] += 1
collision = handle_game_object_collision(game_objects) or check_border_collision(game_objects["player"])
handle_snake_rotation(game_objects)
screen.fill(BLACK)
draw_grid(screen)
# Draw player
first = True
for pos in game_objects["player"]:
color = (100, 0, 255) if first else (255, 0, 0)
pygame.draw.rect(screen, color, (pos[0] * block_size, pos[1] * block_size, block_size, block_size))
first = False
# Display "Collided" text if collision detected
if collision:
text = font.render("Game Ended", True, WHITE)
screen.blit(text, (10, 10))
end_game = True
# Draw fruits
for fruit in ["fruit_1", "fruit_2"]:
pygame.draw.rect(screen, (0, 255, 0), (
game_objects[fruit][0] * block_size, game_objects[fruit][1] * block_size, block_size, block_size))
pygame.display.flip()
# Cap the frame rate
clock.tick(clock_speed)
pygame.quit()
sys.exit()
if __name__ == "__main__":
main()
Comments
Post a Comment