Skip to content

Instantly share code, notes, and snippets.

@the-crypt-keeper
Last active January 29, 2025 20:58
Show Gist options
  • Save the-crypt-keeper/4df3f432b3683be3fb294cc53d0480db to your computer and use it in GitHub Desktop.
Save the-crypt-keeper/4df3f432b3683be3fb294cc53d0480db to your computer and use it in GitHub Desktop.

Write a snake game in python using SDL.

Okay, I need to write a snake game in Python using SDL. Let's start by figuring out which Python library uses SDL. I remember that PySDL2 is a wrapper around SDL2, so that's probably the right choice. I'll need to install that first.

Next, the basic structure of a snake game: there's a snake that moves around, eating food and growing. The game ends when the snake hits the wall or itself. So I'll need to handle the game loop, user input for direction changes, collision detection, and rendering.

I should start by initializing the SDL window and renderer. Then set up the game variables: snake position, direction, food position, and the score. The snake can be represented as a list of segments, each with x and y coordinates. The direction will change based on arrow key presses.

For the game loop, I'll need to process events each frame. Check for key presses to change direction, and also check if the window is closing. Then, update the snake's position by moving the head in the current direction. Each time the snake eats the food, the length increases, and a new food is generated. But I have to make sure the new food doesn't spawn on the snake's body.

Collision detection involves checking if the head hits the walls (outside the screen boundaries) or any part of the body. If a collision occurs, the game ends.

Rendering will involve clearing the screen each frame, drawing the snake segments as rectangles, and the food as another rectangle. Also, displaying the score somewhere, maybe in the window title for simplicity.

Wait, how do I handle the timing? The snake's movement should be at a consistent speed. Maybe using a delay in the loop or tracking time to move at regular intervals. Using SDL's timer functions could help, but perhaps a simple delay in the loop would suffice for a basic implementation.

Testing each part step by step. First, get the window up. Then handle input and moving a block. Then add the food and collision detection. Finally, the growing snake and game over condition.

Possible issues: handling the direction changes properly, making sure the snake doesn't reverse direction into itself. For example, if moving right, can't suddenly go left. Need to restrict direction changes to valid ones.

Also, generating food randomly, but ensuring it's not on the snake. That might require a loop to check all snake segments against the new food position.

Putting it all together, the code structure would be something like:

  • Import necessary modules from SDL2.
  • Initialize window and renderer.
  • Set initial variables (snake, direction, food, score).
  • Game loop:
    • Process events (key presses).
    • Update snake position.
    • Check for collisions.
    • Draw everything.
    • Delay to control game speed.

Let me write the code now, step by step, making sure each part is covered.

I'll help you create a Snake game using Python with the SDL library. We'll use the PySDL2 package, which provides Python bindings for SDL2. Here's the implementation:

import sys
import random
from sdl2 import *
from sdl2.ext import *

# Initialize SDL subsystems
SDL_Init(SDL_INIT_VIDEO)

# Game constants
WINDOW_WIDTH = 640
WINDOW_HEIGHT = 480
GRID_SIZE = 20
SNAKE_SPEED = 7

# Directions
UP = (0, -1)
DOWN = (0, 1)
LEFT = (-1, 0)
RIGHT = (1, 0)

class Game:
    def __init__(self):
        self.window = Window("Snake Game", (WINDOW_WIDTH, WINDOW_HEIGHT))
        self.renderer = Renderer(self.window)
        self.factory = SpriteFactory(sprite_type=SOFTWARE)

        self.snake = [(5, 5)]
        self.direction = RIGHT
        self.food = self.generate_food()
        self.score = 0
        self.game_over = False

    def generate_food(self):
        while True:
            food = (random.randint(0, (WINDOW_WIDTH//GRID_SIZE)-1),
                    random.randint(0, (WINDOW_HEIGHT//GRID_SIZE)-1))
            if food not in self.snake:
                return food

    def handle_input(self):
        event = SDL_Event()
        while SDL_PollEvent(event):
            if event.type == SDL_QUIT:
                return False
            if event.type == SDL_KEYDOWN:
                if event.key.keysym.sym == SDLK_UP and self.direction != DOWN:
                    self.direction = UP
                elif event.key.keysym.sym == SDLK_DOWN and self.direction != DOWN:
                    self.direction = DOWN
                elif event.key.keysym.sym == SDLK_LEFT and self.direction != RIGHT:
                    self.direction = LEFT
                elif event.key.keysym.sym == SDLK_RIGHT and self.direction != LEFT:
                    self.direction = RIGHT
                elif event.key.keysym.sym == SDLK_ESCAPE:
                    return False
        return True

    def update(self):
        if self.game_over:
            return

        # Move snake
        head = self.snake[-1]
        new_head = (head[0] + self.direction[0], head[1] + self.direction[1])

        # Check collisions
        if (new_head[0] < 0 or new_head[0] >= WINDOW_WIDTH//GRID_SIZE or
            new_head[1] < 0 or new_head[1] >= WINDOW_HEIGHT//GRID_SIZE or
            new_head in self.snake):
            self.game_over = True
            return

        self.snake.append(new_head)

        # Check food collision
        if new_head == self.food:
            self.score += 1
            self.food = self.generate_food()
        else:
            self.snake.pop(0)

    def render(self):
        self.renderer.clear()

        # Draw snake
        for segment in self.snake:
            x = segment[0] * GRID_SIZE
            y = segment[1] * GRID_SIZE
            self.factory.create_sprite((x, y, GRID_SIZE, GRID_SIZE), color=(0, 255, 0))

        # Draw food
        food_rect = (self.food[0] * GRID_SIZE, self.food[1] * GRID_SIZE, GRID_SIZE, GRID_SIZE)
        self.factory.create_sprite(food_rect, color=(255, 0, 0))

        # Update title with score
        self.window.set_title(f"Snake Game - Score: {self.score}")
        self.renderer.present()

    def run(self):
        running = True
        last_frame = 0

        while running:
            current_time = SDL_GetTicks()
            if current_time - last_frame > 1000 // SNAKE_SPEED:
                last_frame = current_time
                running = self.handle_input()
                self.update()
                self.render()

        SDL_Quit()

if __name__ == "__main__":
    game = Game()
    game.run()

To run this game:

  1. First install the required packages:

    pip install PySDL2
  2. Save the code in a file (e.g., snake_game.py)

  3. Run the file using Python

How to play:

  • Use arrow keys to control the snake
  • Eat the red food to grow and score points
  • Avoid hitting walls or yourself
  • Press ESC to quit
  • Score is displayed in window title

Game features:

  • Grid-based movement
  • Simple collision detection
  • Score tracking
  • Food generation avoiding snake body
  • Basic game over detection

The game uses SDL2 for rendering and input handling. The snake moves at a constant speed, and the game features simple collision detection with walls and self-intersection.

For a more complete implementation, you could add:

  • Game over screen
  • Restart functionality
  • Sound effects
  • Increasing difficulty levels
  • Better food spawning algorithm
  • Persistent high scores

llama_perf_sampler_print: sampling time = 154.48 ms / 1785 runs ( 0.09 ms per token, 11554.67 tokens per second) llama_perf_context_print: load time = 338110.94 ms llama_perf_context_print: prompt eval time = 18095.48 ms / 20 tokens ( 904.77 ms per token, 1.11 tokens per second) llama_perf_context_print: eval time = 528966.73 ms / 1771 runs ( 298.68 ms per token, 3.35 tokens per second) llama_perf_context_print: total time = 550260.88 ms / 1791 tokens

Write a snake game in python using SDL.

Okay, the user wants a Snake game written in Python using SDL. I need to figure out how to approach this. SDL in Python... I remember there's a library called PySDL2 that wraps SDL for Python. So, I'll use that. But wait, maybe there's another option. Oh, Pygame is built on SDL, right? So maybe using Pygame would be simpler and more common. The user specifically mentioned SDL, but Pygame is a good way to use SDL without dealing with lower-level details. I should check which one is more appropriate.

Assuming the user prefers a more direct SDL approach, perhaps using PySDL2. But I'm more familiar with Pygame, and it might be easier for the user to run. Let's go with Pygame since it's still SDL under the hood. Also, Pygame is more widely used, so the code examples and support are better.

Now, the structure of a Snake game. The game needs a loop where it handles events, updates the snake's position, checks for collisions, and renders the screen. The snake moves in a grid, changing direction based on user input. The food spawns randomly, and when the snake eats the food, it grows.

First, I'll need to initialize Pygame, set up the window, define some constants for the grid size, screen dimensions, colors. Then, the Snake class will handle the snake's body segments, movement direction, and methods to move, grow, and check collisions. The Food class will handle the positioning of the food.

The main loop will handle the events: checking for key presses to change direction (up, down, left, right). It should prevent the snake from reversing direction, like pressing left when moving right. Then, each frame, the snake moves, checks if it's eaten the food, and if so, the food moves, and the snake grows. Also, collision detection with the walls or itself ends the game.

I need to make sure the movement is grid-based. Each segment is a block, so the snake moves by one block each frame. The speed can be controlled by the frame rate. Using a clock to set the frame rate is essential to make the game playable.

Rendering involves clearing the screen, drawing the snake's segments, the food, and updating the display. Also, handling the game over scenario: when the snake collides with itself or the wall, display a message and wait for a key press to quit.

Wait, Pygame's event loop needs to handle the quit event, like closing the window. Also, using the KEYDOWN event to capture the direction changes. But the user might hold the key, so maybe using the event queue or checking the key states. But for simplicity, using the event queue for direction changes, ensuring only one direction change per frame.

Testing edge cases: when the snake goes out of the screen boundaries. Should the game end, or wrap around? The standard Snake game usually ends when hitting the wall. So, checking if the head's position is outside the grid.

Also, the food should not spawn on the snake's body. The Food class's method to randomly place the food should check against the snake's positions.

Putting this all together. The code will start by importing Pygame, defining the constants, then the classes for Snake and Food. The main function initializes the game, creates the snake and food objects, and enters the game loop. Each iteration of the loop processes input, updates the game state, renders everything, and checks for game over.

Potential issues to consider: the timing of the movement. Using a fixed time step with clock.tick() to control the speed. Also, the direction handling—making sure the snake can't reverse direction instantly.

Finally, after the game over, the loop breaks, and the game exits.

I think that covers the main parts. Now, writing the code step by step, making sure each part is explained in comments, and testing it to ensure it works.

Here's a Snake game implementation using Python with Pygame (which is built on SDL). Make sure you have Pygame installed (pip install pygame):

import pygame
import random
import time

# Initialize Pygame
pygame.init()

# Constants
WIDTH = 640
HEIGHT = 480
GRID_SIZE = 20
GRID_WIDTH = WIDTH // GRID_SIZE
GRID_HEIGHT = HEIGHT // GRID_SIZE

# Colors
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
GREEN = (0, 255, 0)
RED = (255, 0, 0)

# Directions
UP = (0, -1)
DOWN = (0, 1)
LEFT = (-1, 0)
RIGHT = (1, 0)

class Snake:
    def __init__(self):
        self.body = [(GRID_WIDTH // 2, GRID_HEIGHT // 2)]
        self.direction = RIGHT
        self.add_segment = False

    def move(self):
        if self.add_segment:
            new_body = self.body[:]
            self.add_segment = False
        else:
            new_body = self.body[:-1]

        head = self.body[0]
        new_head = (head[0] + self.direction[0], head[1] + self.direction[1])
        new_body.insert(0, new_head)
        self.body = new_body

    def grow(self):
        self.add_segment = True

    def check_collision(self):
        head = self.body[0]
        # Wall collision
        if (head[0] < 0 or head[0] >= GRID_WIDTH or
            head[1] < 0 or head[1] >= GRID_HEIGHT):
            return True
        # Self collision
        if head in self.body[1:]:
            return True
        return False

    def change_direction(self, direction):
        if (direction[0] * self.direction[0] != -1 and
            direction[1] * self.direction[1] != -1):
            self.direction = direction

class Food:
    def __init__(self):
        self.position = (0, 0)
        self.randomize()

    def randomize(self):
        self.position = (random.randint(0, GRID_WIDTH-1),
                         random.randint(0, GRID_HEIGHT-1))

def main():
    # Initialize screen
    screen = pygame.display.set_mode((WIDTH, HEIGHT))
    pygame.display.set_caption("Snake Game")

    snake = Snake()
    food = Food()
    game_over = False
    last_update = 0
    update_interval = 0.15

    # Main loop
    running = True
    while running:
        current_time = time.time()
        events = pygame.event.get()

        for event in events:
            if event.type == pygame.QUIT:
                running = False
            elif event.type == pygame.KEYDOWN:
                if game_over:
                    running = False
                else:
                    if event.key == pygame.K_UP:
                        snake.change_direction(UP)
                    elif event.key == pygame.K_DOWN:
                        snake.change_direction(DOWN)
                    elif event.key == pygame.K_LEFT:
                        snake.change_direction(LEFT)
                    elif event.key == pygame.K_RIGHT:
                        snake.change_direction(RIGHT)

        if not game_over and current_time - last_update > update_interval:
            snake.move()
            last_update = current_time

            # Check food collision
            if snake.body[0] == food.position:
                snake.grow()
                food.randomize()

            # Check game over
            if snake.check_collision():
                game_over = True

        # Draw
        screen.fill(BLACK)

        # Draw snake
        for segment in snake.body:
            pygame.draw.rect(screen, GREEN,
                             (segment[0]*GRID_SIZE, segment[1]*GRID_SIZE,
                              GRID_SIZE-1, GRID_SIZE-1))

        # Draw food
        pygame.draw.rect(screen, RED,
                         (food.position[0]*GRID_SIZE, food.position[1]*GRID_SIZE,
                          GRID_SIZE-1, GRID_SIZE-1))

        if game_over:
            font = pygame.font.Font(None, 36)
            text = font.render("Game Over! Press any key to quit", True, WHITE)
            screen.blit(text, (WIDTH//2 - text.get_width()//2,
                               HEIGHT//2 - text.get_height()//2))

        pygame.display.flip()

    pygame.quit()

if __name__ == "__main__":
    main()

This implementation includes:

  1. Basic snake movement and growth mechanics
  2. Food spawning
  3. Collision detection (walls and self)
  4. Game over state
  5. Simple graphics using SDL through Pygame

Key features:

  • Grid-based movement
  • Arrow key controls
  • Constant speed updates (every 0.15 seconds)
  • Simple collision detection
  • Clear game over state

To play:

  1. Install Pygame
  2. Run the script
  3. Use arrow keys to control the snake
  4. Collect red food squares to grow
  5. Avoid hitting walls or yourself

The snake moves at a constant speed, and the game ends when you hit a wall or the snake's own body. The game window will automatically close when you press any key after game over.

llama_perf_sampler_print: sampling time = 212.35 ms / 2025 runs ( 0.10 ms per token, 9535.96 tokens per second) llama_perf_context_print: load time = 339343.46 ms llama_perf_context_print: prompt eval time = 16805.24 ms / 20 tokens ( 840.26 ms per token, 1.19 tokens per second) llama_perf_context_print: eval time = 630407.57 ms / 2011 runs ( 313.48 ms per token, 3.19 tokens per second) llama_perf_context_print: total time = 695363.50 ms / 2031 tokens

@the-crypt-keeper
Copy link
Author

With -t 0.6 --min_p 0.05 we get a working snake game

image

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment