How To Make a Game With Python

Posted in /  

How To Make a Game With Python
vinaykhatri

Vinay Khatri
Last updated on March 19, 2024

    Python is one of the simplest and straightforward programming languages, that make it easy for the developer to put logic simply, without worrying about the complex syntax of the programing language. And what could be more logical than writing the code for a game in a programming language?

    When it comes to development with Python, rather than building the complete project from scratch we as a Python developer uses open source libraries and frameworks to build our projects. With that, we do not have to reinvent the wheel and get through our project easily.

    And this is also one of the main features of Python why many developers love to code with Python. The plethora of libraries and frameworks really help the Python developers to get quickly started with the Project. Although Python has many applications, but in the Gaming development industry, developers do not prefer Python to build real-world or complex games, because of its speed.

    Still, we have many libraries present in Python, which can be used in Game Development with Python. Amongst all the libraries "PyGame" is the most popular Python Game Development library. And in this tutorial, we will learn what is Pygame in Python, how to get started with PyGame and we will also build a snake game using Python and PyGame library.

    What is Pygame?

    Writing the Code from scratch for a software or application could be a nightmare for any developer. And for Game development where we have multiple things going on, such as keypress events, graphics, display movement, sound, etc. there we need some tools that can handle all these things, so we can only focus on the logic of the Game, rather than writing multiple lines of code just to load an image or print graphics on the screen. Here comes the Python "Pygame" library, as the name suggests, it is a Python module that is generally used to build games using Python.

    It is an open-source third-party library, and it contains many useful functions and modules for game development. With Pygame the developer does not need to worry about drawing graphics, playing sound, key events, or loading images on the screen.

    Apart from all the modules and functions provided by the Pygame library, there are many features and functions it misses. It does not support any inbuilt feature for drag and drop, and Physics. A new Python learner who is just getting started with Python intermediate programming can learn and use Pygame to built logic for Games.

    Get Started With Pygame

    The first step toward building games using Pygame is installing the Pygame for your Python environment. To install Pygame we can use the Python pip install terminal command.

    pip install pygame

    After installing the Pygame library we can start writing our first game script with Python and Pygame.

    How to Make Game with Python: A Snake Game with Python and Pygame

    We all have played the simple snake game, where the snake eats an apple or prey which increases its length and speed. And if the snakehead collides with its body or wall the game gets over. To build the game we will create a directory by the name Snake Game where we will store our game main.py file with other resources such as snake block , game title logo , and apple images. Our Working directory will be in the following order.

    Snake Game:.
    ????main.py
    ????resources
           apple.png
           game_icon.png
           snake_block.png

    [caption id="attachment_12019" align="alignleft" width="110"]

    game_icon.png[/caption] [caption id="attachment_12020" align="alignleft" width="96"]

    snake_block.png[/caption] [caption id="attachment_12020" align="alignleft" width="96"]

    apple.png[/caption]

    You can also download these images and store them in the resources directory. Now let's open your favorite Python IDE or text editor and start writing code in main.py file. We will start with importing the required modules.

    import pygame
    import time
    import random

    Both random and time are the Python's inbuilt modules, and in the game, we will be using these modules for time delay and generating random coordinates for the apple. The code for the complete game is more than 250 lines so it would be great that we divide the complete code into multiple functions or modules. It will make the code more readable, and reusable. After importing the important modules let's write the snake movement functions that will be responsible for the changing direction of the snake movement. The snake can move in four directions up, down, left, and right so we need to define 4 functions.

    # snake movement
    def move_left():
        global direction
        direction="left"
    
    def move_right():
        global direction
        direction="right"
    
    def move_up():
        global direction
        direction="up"
    
    def move_down():
        global direction
        direction="down"

    In all the movement functions we are accessing the direction identifier with global keyword because we are changing the direction global variable identifier inside the functions and we want to reflect that changes outside the function too. To know more about how the global and local scope variables work in Python click here .

    Python is an interpreted programming langauge so it is very important to define the functions in a sequential order before we call them. That's why we are defining the helper functions first so we can call them in the upcoming code section.

    When we play the game we also get a scoreboard that keeps updating when some event occurs. So for our snake game let's define a function player_score that will display the player's live score on the top right corner of the screen.

    # the player score
    def player_score():
        my_score = pygame.font.SysFont("Calibri",20).render(f"Player Score: {snake_length}", True, (255, 255, 255))
        # show player score on the top right corner
        screen.blit(my_score, (700, 10))

    The pygame.font.SysFont() method defines the font of the text and its size. The render() method renders the message on the screen, and it accepts the color code in RGB format. In our game, we have provided the white color with (255, 255, 255) color code. While playing the game, the player may get out for various reasons, such as when the snake hit the walls or itself or the player try to quit the game by pressing the escape button, there we need a function that gets invoke and show the player its final score and automatically quit the game after 4 seconds. For such functionality let's define a game_over() function

    # function when the game is over
    def game_over():
        # change the background color
        screen.fill((255, 255, 255))
        # the Game over message
        my_score = pygame.font.SysFont("Calibri",40).render(f"Game Over Your Score: {snake_length}", True, (0, 0, 0))
        screen.blit(my_score, (150, 350))
        pygame.display.update()
    
        # wait for 4 seconds and close the game
        time.sleep(4)
        exit(0)

    The screen.fill() method will fill the screen with the specified RGB color (255, 255, 255) (white in our case). pygame.font.SysFont() function will set the font of the text. The render() function print the text on the screen. The blit() function print the render message on the specified x and y coordinates. The pygame.display.update() function will update the screen with the specified fill() function color. The sleep(4) function will delay the code execution for 4 seconds. The exit(0) function will stop the program execution close the program. Let's also define dedicated functions that will draw the snake blocks and apple on the screen, so we do not have to write that code again and again in the program, whenever we need to display the snake and apple on the screen.

    # a function to draw the snake on the screen
    def draw_snake_block():
        screen.fill(BACKGROUND_COLOR)
    
        # print all the snae block on the screen
        for i in range(snake_length):
            screen.blit(snake_block, (snake_block_x[i], snake_block_y[i]))
    
        # update the screen
        pygame.display.update()
    
    # draw the apple on the screen
    def draw_apple():
        screen.blit(apple, (apple_x, apple_y))
        pygame.display.update()

    The draw_snake_block() and draw_apple() functions will draw the snakehead, its body, and apple with every iteration of the game running. The game runs in multiple frames and these two functions will help us to draw the snake and apple in every frame. In the Snake game, the snake gets automatically starts walking in the pressed direction. Now we also need to define a function snake_walk() that will specify the snake path walk.

    def snake_walk():
        # access the global variables
        global direction
        global snake_block_x
        global snake_block_y
        global snake_length
    
        """
            when the head direction change
            the body the snake will follow its previous
            snake block
        """
        for i in range(snake_length-1,0,-1):
            snake_block_x[i]= snake_block_x[i-1]
            snake_block_y[i] = snake_block_y[i-1]
    
        # change the snake head direction
        if direction=="up":
            snake_block_y[0]-=block_pixel_size
    
        if direction=="down":
            snake_block_y[0]+=block_pixel_size
    
        if direction=="right":
            snake_block_x[0]+=block_pixel_size
    
        if direction=="left":
            snake_block_x[0]-=block_pixel_size
    
        # draw the snake with every iteration of the game running
        draw_snake_block()

    In the snake_walk() function we are changing the head position of the snake_block_x and snake_block_y coordinates based on the current direction. And inside the for loop, we are just specifying that the body blocks of the snake must follow its previous block. And with each iteration, we are drawing the new coordinates of the snake blocks with draw_snake_block() function. With this function, we will get a moving snake on the screen. Let's also define a function that checks if the snake ate the apple or not. This function will return a boolean value that we will use later in the run() function.

    # function to check if the snake head eat the apple
    def did_snake_eat_apple():
        if snake_block_x[0]>=apple_x and  snake_block_x[0]< apple_x+block_pixel_size: 
            if snake_block_y[0]>=apple_y and  snake_block_y[0]<apple_y+block_pixel_size:
                return True
        return False

    The did_snake_eat_apple() check if the head position of the snake block is colliding with the coordinates of the apple coordinates. When the snake eats an apple we also need to increase the length of the snake and the overall speed of the snake's walk. For that, we can define a function increment_snake_length() .

    # function to increase the snake length
    def increment_snake_length():
        # access the global snake features
        global snake_length
        global snake_block_x
        global snake_block_y
        global SNAKE_SPEED
    
        # increase the snake length by One
        snake_length +=1
    
        # add a new random data in the snake x and y coordinates list
        snake_block_x.append(-1)
        snake_block_y.append(-1)
    
        # increase the snake speed
        if SNAKE_SPEED > 0.2:
            if snake_length %2 ==0:
                SNAKE_SPEED-=0.1

    The append() method will add -1 as a new element or snake block to the snake x and y coordinate blocks. However, the coordinates will be overwritten by the snake_walk() function. Because soon the body blocks update their position with each iteration and they follow the coordinates of the snakehead block. There are two ways the player can lose the game, one is by body collision and the second is the snake collision. The body collision occurs when the snakehead collides with its body, and the wall collision occurs when the snakehead collides with the walls. Let's define two functions snake_collision() and wall_collision() that will over the game when the snake hits the walls or itself.

    # function for snake collision
    def snake_collision():
        ''' if the snake head collide with the
            snake body
            close the game
        '''
        for i in range(1,snake_length):
            if snake_block_x[0]>=snake_block_x[i] and snake_block_x[0]< snake_block_x[i]+20: 
                if snake_block_y[0]>=snake_block_y[i] and snake_block_y[0]<snake_block_y[i]+20:
                    game_over()
    
    # function for the snake-wall collision
    def wall_collision():
        # if snake head hit left wall or right wall
        if snake_block_x[0]<0 or snake_block_x[0] >=screen_size[0]:
            game_over()
        # if the snake head hits the up or down wall
        if snake_block_y[0]<0 or snake_block_y[0] >=screen_size[1]:
            game_over()

    Both snake_collision() and wall_collision() functions call game_over function when the if the condition gets True. Now let's define the run() function that will run our game in multiple frames, and manage all the above-defined functions.

    def run():
        # access the global apple x and y coordinates
    
        global apple_x
        global apple_y
    
        #run the game until the user click on the close button
        game_running = True
        while game_running:
            # loop through all the game events
            for event in pygame.event.get():
                # check if the user click the close button
                if event.type == pygame.QUIT:
                    game_running=False
    
                # snake control system
    
                if event.type == pygame.KEYDOWN:
                    # if player press escape the game ends
                    if event.key == pygame.K_ESCAPE:
                        game_over()
    
                    # to move left
                    if event.key == pygame.K_LEFT:
                        if direction in ["up", "down"]:
                            move_left()
    
                    # to move right
                    if event.key == pygame.K_RIGHT:
                        if direction in ["up", "down"]:
                            move_right()
    
                    # to move up
                    if event.key == pygame.K_UP:
                        if direction in ["left", "right"]:
                            move_up()
    
                    # to move down
                    if event.key == pygame.K_DOWN:
                        if direction in ["left", "right"]:
                            move_down()
            snake_walk()
            draw_apple()
            # check if the snake eat the apple
            if (did_snake_eat_apple()):
                # set new coordinates for the apple
                apple_x = random.randint(1, 29)*block_pixel_size
                apple_y = random.randint(1, 29)*block_pixel_size
                # draw a new apple
                draw_apple()
    
                # increasee the snake length
                increment_snake_length()
    
            # check if the snake head collide with its body
            snake_collision()
            # check if the snake collide with the walls
            wall_collision()
            # update the palyer score
            player_score()
    
            # update the screen
            pygame.display.update()
    
            # the speed of the snake movement
            time.sleep(SNAKE_SPEED)

    Mostly all the run() function statements are inside the while game_running statement. And each iteration of this while loop defines a single frame. The pygame.event.get() function returns an iterator of events which generally represent the keys press by the user. The event.type represents the type of the event. The pygame.QUIT occur when the user clicks on the window close button. The event.key property represents the key pressed by the user. Using this property we called the movement functions of the snake. Now let's define the main section of our program.

    if __name__ =="__main__":
        #Initialize Pygame
        pygame.init()
    
        # width and height of the screen window (w:h)(900:700)
        screen_size = width, height = 900, 700
    
        screen = pygame.display.set_mode(screen_size)
    
        # title and icon of the screen window
        pygame.display.set_caption("Snake Game")
        icon = pygame.image.load("resources/game_icon.png")
        pygame.display.set_icon(icon)
    
        #set the color of the screen window (R,G,B)
        BACKGROUND_COLOR = (0,0,0)   #black
        screen.fill(BACKGROUND_COLOR)
    
        # load the snake block on the screen
        snake_block = pygame.image.load("resources/snake_block.png").convert()
        # convert the snake block to 20X20 pixels
        block_pixel_size = 20
        snake_block = pygame.transform.scale(snake_block, (block_pixel_size, block_pixel_size))
    
        #load apple on the screen window
        apple =  pygame.image.load("resources/apple.png").convert()
        # set the apple size to 20X20 pixels (similar to the snake block size)
        apple=pygame.transform.scale(apple, (block_pixel_size, block_pixel_size))
    
        # initial coordinate of the apple block
        apple_x = 200
        apple_y = 100
    
        # initial snake head coordinate
        snake_block_x=[100,]
        snake_block_y=[100,]
    
        # initial length of the snake
        snake_length =1
    
        # intial direction of the snake movement
        direction ="right"
    
        # initial snake speed
        SNAKE_SPEED = 1
    
        # place snake block on the window screen
        screen.blit(snake_block, (snake_block_x[0], snake_block_y[0]))
        # place apple on the window
        screen.blit(apple, (apple_x, apple_y))
    
        # update the window screen to render the snake block
        pygame.display.update()
    
        # call the run function
        run()

    The pygame.init() method initialize the pygame object, and it is very necessary to write this statement. The display.set_mode() function specifies the screen size of the window. The display.set_caption() specify the title of the screen window. The image.load() function load the image in this program. The display.set_icon() specify the window icon. The fill() function fill the background of the window with the specified RGB color. The transform.scale() function scale the image into specified pixel size (width, height). apple_x, and apple_y identifiers specify the initial coordinates of the apple on the screen. snake_block_x, and snake_block_y lists represent the coordinates of the snakehead its body. The blit() method renders the images on the screen. The update method is important to print the images on the screen. That's all with the coding, now put all the code together and execute.

    Snake Game With Python and Pygame

    import pygame
    import time
    import random
    
    # snake movement
    def move_left():
        global direction
        direction="left"
    
    def move_right():
        global direction
        direction="right"
    
    def move_up():
        global direction
        direction="up"
    def move_down():
        global direction
        direction="down"
    
    # the player score
    def player_score():
        my_score = pygame.font.SysFont("Calibri",20).render(f"Player Score: {snake_length}", True, (255, 255, 255))
        # show player score on the top right corner
        screen.blit(my_score, (700, 10))
    
    # function when the game is over
    def game_over():
        # change the background color
        screen.fill((255, 255, 255))
        # the Game over message
        my_score = pygame.font.SysFont("Calibri",40).render(f"Game Over Your Score: {snake_length}", True, (0, 0, 0))
        screen.blit(my_score, (150, 350))
        pygame.display.update()
    
        # wait for 4 seconds and close the game
        time.sleep(4)
        exit(0)
    
    # a function to draw the snake on the screen
    def draw_snake_block():
        screen.fill(BACKGROUND_COLOR)
    
        # print all the snae block on the screen
        for i in range(snake_length):
            screen.blit(snake_block, (snake_block_x[i], snake_block_y[i]))
    
        # update the screen
        pygame.display.update()
    
    # draw the apple on the screen
    def draw_apple():
        screen.blit(apple, (apple_x, apple_y))
        pygame.display.update()
    
    def snake_walk():
        # access the global variables
        global direction
        global snake_block_x
        global snake_block_y
        global snake_length
    
        """
            when the head direction change
            the body the the snake will follow its previous
            snake block
        """
        for i in range(snake_length-1,0,-1):
            snake_block_x[i]= snake_block_x[i-1]
            snake_block_y[i] = snake_block_y[i-1]
    
        # change the snake head direction
        if direction=="up":
            snake_block_y[0]-=block_pixel_size
    
        if direction=="down":
            snake_block_y[0]+=block_pixel_size
    
        if direction=="right":
            snake_block_x[0]+=block_pixel_size
    
        if direction=="left":
            snake_block_x[0]-=block_pixel_size
    
        # draw the snake with every iteration of the game running
        draw_snake_block()
    
    
    # function to check if the snake head eat the apple
    def did_snake_eat_apple():
        if snake_block_x[0]>=apple_x and  snake_block_x[0]< apple_x+block_pixel_size:
            if snake_block_y[0]>=apple_y and  snake_block_y[0]<apple_y+block_pixel_size:
                return True 
        return False 
    
    # function to increase the snake length 
    def increment_snake_length(): 
        # access the gloabl snake features 
        global snake_length 
        global snake_block_x 
        global snake_block_y 
        global SNAKE_SPEED 
        
        # increase the snake length by One 
        snake_length +=1 
        
        # add a new random data in the snake x and y coordinates list 
        snake_block_x.append(-1) 
        snake_block_y.append(-1) 
        
        # increase the snake speed 
        if SNAKE_SPEED > 0.2:
            if snake_length %2 ==0:
                SNAKE_SPEED-=0.1
    
    # function for snake collision
    def snake_collision():
        ''' if the snake head collide with the
            snake body
            close the game
        '''
        for i in range(1,snake_length):
            if snake_block_x[0]>=snake_block_x[i] and snake_block_x[0]< snake_block_x[i]+20:
                if snake_block_y[0]>=snake_block_y[i] and snake_block_y[0]<snake_block_y[i]+20:
                    game_over()
    
    # function for the snake-wall collision
    def wall_collision():
        # if snake head hit left wall or right wall
        if snake_block_x[0]<0 or snake_block_x[0] >=screen_size[0]:
            game_over()
        # if the snake head hits the up or down wall
        if snake_block_y[0]<0 or snake_block_y[0] >=screen_size[1]:
            game_over()
    
    def run():
        # access the global apple x and y coordinates
    
        global apple_x
        global apple_y
    
        #run the game until the user click on the close button
        game_running = True
        while game_running:
            # loop through all the game events
            for event in pygame.event.get():
                # check if the user click the close button
                if event.type == pygame.QUIT:
                    game_running=False
    
                # snake control system
    
    
                if event.type == pygame.KEYDOWN:
                    # if player press escape the game ends
                    if event.key == pygame.K_ESCAPE:
                        game_over()
    
                    # to move left
                    if event.key == pygame.K_LEFT:
                        if direction in ["up", "down"]:
                            move_left()
    
                    # to move right
                    if event.key == pygame.K_RIGHT:
                        if direction in ["up", "down"]:
                            move_right()
    
                    # to move up
                    if event.key == pygame.K_UP:
                        if direction in ["left", "right"]:
                            move_up()
    
                    # to move down
                    if event.key == pygame.K_DOWN:
                        if direction in ["left", "right"]:
                            move_down()
            snake_walk()
            draw_apple()
            # check if the snake eat the apple
            if (did_snake_eat_apple()):
                # set new coordinates for the apple
                apple_x = random.randint(1, 29)*block_pixel_size
                apple_y = random.randint(1, 29)*block_pixel_size
                # draw a new apple
                draw_apple()
    
                # increasee the snake length
                increment_snake_length()
    
            # check if the snake head collide with its body
            snake_collision()
            # check if the snake collide with the walls
            wall_collision()
            # update the palyer score
            player_score()
    
            # update the screen
            pygame.display.update()
    
            # the speed of the snake movement
            time.sleep(SNAKE_SPEED)
    
    if __name__ =="__main__":
        #Initialize Pygame
        pygame.init()
    
        # width and height of the screen window (w:h)(900:700)
        screen_size = width, height = 900, 700
    
        screen = pygame.display.set_mode(screen_size)
    
        # title and icon of the screen window
        pygame.display.set_caption("Snake Game")
        icon = pygame.image.load("resources/game_icon.png")
        pygame.display.set_icon(icon)
    
    
        #set the color of the screen window (R,G,B)
        BACKGROUND_COLOR = (0,0,0)   #black
        screen.fill(BACKGROUND_COLOR)
    
        # load the snake block on the screen
        snake_block = pygame.image.load("resources/snake_block.png").convert()
        # convert the snake block to 20X20 pixels
        block_pixel_size = 20
        snake_block = pygame.transform.scale(snake_block, (block_pixel_size, block_pixel_size))
    
        #load apple on the screen window
        apple =  pygame.image.load("resources/apple.png").convert()
        # set the apple size to 20X20 pixels (similar to the snake block size)
        apple=pygame.transform.scale(apple, (block_pixel_size, block_pixel_size))
    
        # initial coordinate of the apple block
        apple_x = 200
        apple_y = 100
    
        # initial snake head coordinate
        snake_block_x=[100,]
        snake_block_y=[100,]
    
        # initial length of the snake
        snake_length =1
    
        # intial direction of the snake movement
        direction ="right"
    
        # initial snake speed
        SNAKE_SPEED = 1
    
        # place snake block on the window screen
        screen.blit(snake_block, (snake_block_x[0], snake_block_y[0]))
        # place apple on the window
        screen.blit(apple, (apple_x, apple_y))
    
        # update the window screen to render the snake block
        pygame.display.update()
    
        # call the run function
        run()

    Output

    Wrapping Up!

    In this Python tutorial, we learned what is Pygame and how can we use it to build simple games in Python. If you are into Game Development then Python is not an ideal language, although we can run the game build on Pygame and Python on Android devices using pgs4a, it is not suggested to use Python for complex game development. It's fun to know how to use Libraries like Pygame and TKinter to implement graphics and game logic using Python. You can also convert the above snake game main.py file into a window executable exe file. To know how to convert a Python program to executable windows exe file click here .

    People are also reading:

    Leave a Comment on this Post

    0 Comments