Build a snake game in Python Day-6

May 07, 2020 ( last updated : May 08, 2020 )
Python pygame

https://github.com/cao-weiwei/


😃Today I will introduce the vital part of the game which is the key class here.

The Board Class

Before introducing the Board class, let’s talk about some predefined variables that we will use and don’t have strong connections with other class. Basically, there are the parameters about the screen size and color and texts.

# Define the colors in RGB format
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
BLUE = (0, 0, 255)
BLUE_BUTTON = (80, 118, 249)
GREEN = (80, 255, 120)
GREEN_BG = (142, 204, 57)
BRI_GREEN = (200, 255, 200)
DARK_GREEN = (50, 150, 50)
RED = (200, 0, 0)
RED_BUTTON = (255, 50, 50)
BRI_RED = (255, 200, 200)
DARK_RED = (150, 50, 50)
BLOODY = (100, 0, 0)
GREY = (100, 100, 100)

# Define the size of the window and cell
WIDTH, HEIGHT = 800, 600
ROWS, COLS = 30, 40
W_CELL, H_CELL = WIDTH // COLS, HEIGHT // ROWS

# Background songs and images
BGM = "bgm_1.wav"
BG_PIC = "page_1.png"

# Speed
EASY = 10
MEDIUM = 20
HARD = 50

# Captions
WELCOME_TXT = "Welcome to Play Snake!"
GAME_OVER_TXT = "Game Over!"
START_BUTTON_TXT = "Start"
QUIT_BUTTON_TXT = "Quit"

# Fonts
ARIAL = "arial"
GEORGIA = "georgiaboldttf"

The next is the main part here:

  1. first is the construtor of Board class, we define the game and other essential variables here.
    def __init__(self):
        """
        Initialize all related modules and the screen
        """
        # 0. initialize all modules and music
        pygame.init()
        pygame.mixer.init()
        # 1. set a screen
        self.window_size = WIDTH, HEIGHT
        self.window = pygame.display.set_mode(self.window_size)
        pygame.display.set_caption("Snake v1.0")
        self.window.fill(GREY)
        self.clock = pygame.time.Clock()
        # 2. set game status
        self.is_quit = False
        self.is_start = False
        # 3. set font and image
        self.title_font = pygame.font.SysFont(GEORGIA, 55)
        self.button_font = pygame.font.SysFont(GEORGIA, 20)
        self.normal_font = pygame.font.SysFont(GEORGIA, 30)
        self.bg_pic = pygame.image.load(BG_PIC)
        self.btn_start = Button.Button((220, 450), (110, 40), (250, 457), START_BUTTON_TXT)
        self.btn_quit = Button.Button((520, 450), (110, 40), (550, 457), QUIT_BUTTON_TXT)
  1. The next is a method that draws objects on the board. There are three types of objects, Food, Snake and Button. So, this method can draw any instances of the given classes.
    def draw_objects(self, obj: object, color: tuple) -> None:
        """
        Draw objects on the screen
        :param color: the color of objects
        :param obj: instance of an object that should be drawn on the screen
        :return: None
        """
        if isinstance(obj, Food.Food):  # case 1: draw food
            food_pos = obj.get_position()
            pygame.draw.rect(self.window, color, (food_pos[0], food_pos[1], W_CELL, H_CELL))
        elif isinstance(obj, Snake.Snake):  # case 2: draw a snake
            snake_pos = obj.get_position()
            for left, top in snake_pos:
                pygame.draw.rect(self.window, color, (left, top, W_CELL, H_CELL), 2)  # rect=(left,top,w_cell,h_cell), border of snake
        elif isinstance(obj, Button.Button):  # case 3: draw a button
            button_pos = obj.get_position()
            button_size = obj.get_size()
            button_txt = obj.get_text()
            pygame.draw.rect(self.window, color, (button_pos[0], button_pos[1], button_size[0], button_size[1]))  # button
            pygame.draw.rect(self.window, WHITE, (button_pos[0], button_pos[1], button_size[0], button_size[1]), 2)  # border
            text_font = self.button_font.render(button_txt[0], True, WHITE)  # text
            self.window.blit(text_font, button_txt[1])
  1. This intro_gamemethod will do the jobs at very beginning, the interface you see a snake and an apple with two buttons. If user click the start button, it will change the game sataus and call the play_gamemethod, other will it will directly close the window to quit the game.
    def intro_game(self) -> None:
        """
        An interface the before user starting the game.
        If user click start, it will call the play_game() method
        If user click quit, it will close the window
        :return: None
        """
        # 0. to check which buttons are clicked
        while not self.is_start:
            # 0.1. draw welcome screen
            self.clock.tick(HARD)
            text = self.title_font.render(WELCOME_TXT, True, WHITE)
            self.window.blit(self.bg_pic, (0, 0))
            self.window.blit(text, (60, 110))
            # 0.2 listen to the events
            for event in pygame.event.get():# set background font and put it on the screen
                print(event)
                if event.type == pygame.QUIT:
                    pygame.quit()
                    quit()

            # draw buttons including 'start' and 'quit' and listening mouse actions
            mouse_pos = pygame.mouse.get_pos()
            mouse_click = pygame.mouse.get_pressed()
            self.draw_objects(self.btn_start, BLUE_BUTTON)
            self.draw_objects(self.btn_quit, RED_BUTTON)
            if self.btn_start.is_hover(mouse_pos):
                if self.btn_start.is_click(mouse_click):
                    self.is_start = True
                    break
            else:
                self.draw_objects(self.btn_start, BLUE)
            if self.btn_quit.is_hover(mouse_pos):
                if self.btn_quit.is_click(mouse_click):
                    self.is_quit = True
                    break
            else:
                self.draw_objects(self.btn_quit, RED)
            # update the screen
            pygame.display.update()

        if self.is_start:
            self.play_game()
            self.is_start = False
        if self.is_quit: pygame.quit()
  1. When the start button is clicked, the it will show a moving snake and food on the screen. User can use arrow keys to move the snake for eating food. This process is finished by following piece of code:
    def play_game(self) -> None:
        """
        The main part for starting a game
        :return: None
        """
        # 0. play background music
        bgm_obj = pygame.mixer.Sound(BGM)
        bgm_obj.play(-1)
        # 1. get food and snake coordinates and draw objects on the screen
        food = Food.Food()
        snake = Snake.Snake()
        self.draw_objects(food, RED_BUTTON)
        self.draw_objects(snake, BLUE_BUTTON)
        # 2. others settings
        direction = "right"  # default next direction of the snake
        score = snake.get_length()  # get current length of the snake
        clock = pygame.time.Clock()  # generate a Clock Object for setting the speed of snake
        # 3. Main loop until the user lose or close the game.
        while not self.is_quit:
            # 3.0 This limits the while loop to a max of HARD times per second.
            clock.tick(HARD)
            # 3.1 Draw current scores on the left top of the screen
            self.window.fill(GREEN_BG)
            score = snake.get_length()
            total_score = self.button_font.render("Scores: " + str(score), True, WHITE)
            self.window.blit(total_score, (5, 0))
            # 3.2 Listen to the event,
            # to determine the game whether is still working or getting keys from users
            for event in pygame.event.get():
                if event.type == pygame.QUIT:  # close the game
                    print(f"event.type = {event.type}")
                    self.is_quit = True
                    break

                if event.type == pygame.KEYDOWN:  # receive command
                    if event.key == pygame.K_RIGHT:
                        print("*" * 30 + "right" + "*" * 30)
                        direction = "right"
                    elif event.key == pygame.K_LEFT:
                        print("*" * 30 + "left" + "*" * 30)
                        direction = "left"
                    elif event.key == pygame.K_UP:
                        print("*" * 30 + "up" + "*" * 30)
                        direction = "up"
                    elif event.key == pygame.K_DOWN:
                        print("*" * 30 + "down" + "*" * 30)
                        direction = "down"
            # 3.3 update coordinates of the snake after receiving command from user
            print('-' * 70)
            snake.move(direction)
            if not snake.is_alive():  # check whether the snake is sill alive
                break
            if food.is_eaten(snake):  # check whether the food is still exists
                snake.eat(food)
                food.update_position()
                while food.is_eaten(snake): food.update_position()  # put another food except the range of snake
            # 3.4 all is good then draw the snake and food
            self.draw_objects(snake, BLUE_BUTTON)
            self.draw_objects(food, RED_BUTTON)
            # 3.5 update the screen with what we've drawn
            pygame.display.update()

        # 4. close the game
        if self.is_quit:
            pygame.quit()
        else:
            bgm_obj.stop()
            self.end_game(score)
  1. If the snake doesn’t alive anymore the current round is over, user can play again or quit the game, this job is done by the method of end_game:
    def end_game(self, score: int) -> None:
        """
        End the current running game it will give options to user to choose a new round or exit the game
        :param score: current game scores
        :return: None
        """
        # 0. set a game over screen, including text and its color position
        self.window.fill(GREEN_BG)
        text = self.title_font.render(GAME_OVER_TXT, True, WHITE)
        self.window.blit(text, (240, 200))
        total_score = self.normal_font.render("Total Scores: " + str(score), True, WHITE)
        self.window.blit(total_score, (290, 290))
        pygame.display.update()

        while not self.is_quit:
            for event in pygame.event.get():  # wait for clicking to close the window
                if event.type == pygame.QUIT:
                    self.is_quit = True
                    break
            # draw buttons including 'start' and 'quit' and listening mouse actions
            mouse_pos = pygame.mouse.get_pos()  # get current moust status
            mouse_click = pygame.mouse.get_pressed()
            self.draw_objects(self.btn_start, BLUE_BUTTON)  # draw buttons
            self.draw_objects(self.btn_quit, RED_BUTTON)
            if self.btn_start.is_hover(mouse_pos):  # if click 'start'
                if self.btn_start.is_click(mouse_click):
                    self.is_start = True
                    break
            else:
                self.draw_objects(self.btn_start, BLUE)
            if self.btn_quit.is_hover(mouse_pos):  # if click 'quit
                if self.btn_quit.is_click(mouse_click):
                    self.is_quit = True
                    break
            else:
                self.draw_objects(self.btn_quit, RED)
            # update the screen
            pygame.display.update()  # update objects on the screen

        if self.is_start: self.play_game()
        if self.is_quit: pygame.quit()

Above is all the code of snake game, hope it helpful for you 🥳

snake_02_1st_glance


If you like my articles please give me a star or leave comments below, thanks!

Originally published May 07, 2020
Latest update May 08, 2020

Related posts :