Snake version 1

The code of the classic Snake game. First version. Version 2 in the next post.

The Gameplay

I would like to make some smooth movements, instead of going forwand of one “cell” at the time. Maybe in the next posts we could try to do that.

The code of Snake

import pygame
from pygame import gfxdraw
from random import randrange


# Define Constants

BOARD_SIZE = 20  # Size of the board, in block
BLOCK_SIZE = 20  # Size of 1 block, in pixel
GAME_SPEED = 8  # Game speed (Normal = 10), The bigger, the faster
SIZE = (BOARD_SIZE * BLOCK_SIZE, BOARD_SIZE * BLOCK_SIZE) # 400 x 400
# Surface
window = pygame.display.set_mode(SIZE)
pygame.display.set_caption("Python Snake")
score = 0


# ============================ THE SNAKE POSITION AND BEHAVIOUR ======

class Snake():
    def __init__(self):
        self.starting_position()

    def starting_position(self):
        "The coordinates of the start and direction are here"

        self.head = [
            # self.head[0] = x = 5
            int(BOARD_SIZE / 4),
            # self.head[1] = x = 5
            int(BOARD_SIZE / 4)]
        self.body = [[self.head[0], self.head[1]],
                     [self.head[0] - 1, self.head[1]],
                     [self.head[0] - 2, self.head[1]]
                     ]
        #   [ ][ ][ ] => right
        self.direction = "RIGHT"
        # Conditions to not go in the opposite direction

    def direction_to(self, direction):
        "When you hit a key in the while loop; avoid going backwards"
        opposites = [("RIGHT", "LEFT"),("UP", "DOWN")]
        for a, z  in opposites:
            if self.direction == a:
                if not direction == z:
                    self.direction = direction
                    break
            if self.direction == z:
                if not direction == a:
                    self.direction = direction
                    break

    def move(self, food_pos):
        moves = {
        "RIGHT": (0, 1),
        "LEFT": (0, -1),
        "UP" : (1, -1),
        "DOWN": (1, 1)
        }
        for k in moves:
            if self.direction == k:
                self.head[moves[k][0]] += moves[k][1]

        self.body.insert(0, list(self.head))
        if self.head == food_pos:
            return 1
        else:
            "If do not eat... same size"
            self.body.pop()
            return 0

    def check_collision(self):
        # Checks collision with border or himself

        conditions = (
            # x
            self.head[0] >= 20 or self.head[0] < 0,
            # y
            self.head[1] > 19 or self.head[1] < 0,
            # self
            [x for x in self.body[1:] if self.head == x]
        )
        if any(conditions):
            return 1
        else:
            return 0

# ============================= SPAWN FOOD =======================

class FoodSpawner():
    def __init__(self):
        self.food_pos = self.randompos()
        self.there_is_food = True

    def spawn_food(self):
        if self.there_is_food == False:
            self.food_pos = self.randompos()
            self.there_is_food = True
        return self.food_pos

    def set_food_on_screen(self, bool_value):
        self.there_is_food = bool_value

    def randompos(self):
        return [randrange(1, 20), randrange(1, 20)]


# ===================== DRAW HEAD, BODY and FOOD ================

class Draw:
    def draw_head(pos):
        pygame.draw.rect(
            window,
            (0, 255, 0),
            pygame.Rect(
                pos[0] * BLOCK_SIZE,
                pos[1] * BLOCK_SIZE,
                BLOCK_SIZE,
                BLOCK_SIZE))

    def draw_body(pos):
        pygame.draw.rect(window, (0, 128, 0), pygame.Rect(pos[0] * BLOCK_SIZE, pos[1] * BLOCK_SIZE, BLOCK_SIZE, BLOCK_SIZE))

    def delete_tail(pos):
        pygame.draw.rect(window, (0, 0, 0), pygame.Rect(snake.body[-1][0] * BLOCK_SIZE, snake.body[-1][1] * BLOCK_SIZE, BLOCK_SIZE, BLOCK_SIZE))

    def delete_fruit(pos, food_pos):
        x = food_pos[0] * BLOCK_SIZE + 10
        y = food_pos[1] * BLOCK_SIZE + 10
        r = 9
        gfxdraw.filled_circle(window, x, y, r, (0, 0, 0))

    def draw_fruit(food_pos):
        gfxdraw.filled_circle(window, food_pos[0] * BLOCK_SIZE + 10, food_pos[1] * BLOCK_SIZE + 10, 9, (255, 0, 0))

    def text_surface(text_to_show, x=0, y=0, middle="both"):
        "It write in the middle by default, if not middle='both' middle='x'"
        text = font.render(text_to_show, 1, pygame.Color("Coral"))
        if middle == "x":
            text_rect = text.get_rect(center=((SIZE[0] // 2, y)))
            window.blit(text, text_rect)      
        elif middle == "both":
            text_rect = text.get_rect(center=((SIZE[0] // 2, SIZE[1] // 2)))
            window.blit(text, text_rect)
        else:
            window.blit(text, (x, y))
        pygame.display.update()


# ================================= MANAGE GAME PART =================

class Game:
    clock = pygame.time.Clock()
    
    def restart():
        global GAME_SPEED

        GAME_SPEED = 8
        window.fill((0, 0, 0))
        snake.starting_position()
        Game.start()


    def press_to_start():
        "Initial menu"
        global loop, snake, food
        global font, size

        pygame.init()
        font = pygame.font.SysFont("Arial", 24)
        snake = Snake()
        food = FoodSpawner()
        Draw.text_surface("Python vs Snake", y=30, middle="x")
        Draw.text_surface("Press s to start")
        while True:
            event = pygame.event.wait()
            if event.type == pygame.QUIT:
                loop = 0
                break
            if event.type == pygame.KEYDOWN:
                if event.key == pygame.K_ESCAPE:
                    loop = 0
                    break
                if event.key == pygame.K_s:
                    Game.restart()
                    break
        pygame.quit()


    def start():
        global GAME_SPEED, score, loop

        food_pos = food.spawn_food()
        loop = 1
        while loop:
            if pygame.event.get(pygame.QUIT):
                loop = 0
            pygame.event.pump()
            keys = pygame.key.get_pressed()
            if keys[pygame.K_ESCAPE]:
                loop = 0
            if keys[pygame.K_UP]:
                snake.direction_to("UP")
            if keys[pygame.K_DOWN]:
                snake.direction_to("DOWN")
            if keys[pygame.K_RIGHT]:
                snake.direction_to("RIGHT")
            if keys[pygame.K_LEFT]:
                snake.direction_to("LEFT")
            if snake.move(food_pos) == 1:
                # delete_fruit(pos, food_pos)
                score += 1
                food.set_food_on_screen(False)
                GAME_SPEED += 1
                food_pos = food.spawn_food()

            head = 1
            for pos in snake.body:
                if head == 1:
                    Draw.draw_head(pos)
                    head = 0
                else:
                    Draw.draw_body(pos)
            Draw.delete_tail(pos)
            Draw.draw_fruit(food_pos)

            if snake.check_collision() == 1:
                loop = 0
                Game.press_to_start()
            pygame.display.update()
            Game.clock.tick(GAME_SPEED)

        pygame.quit()

Game.press_to_start()

 

Published by pythonprogramming

Started with basic on the spectrum, loved javascript in the 90ies and python in the 2000, now I am back with python, still making some javascript stuff when needed.