Create a Flappy Bird Clone With Python P2

Posted in tutorials python -

This is one part of a multi-part tutorial. To see other posts in the same series, please click below:

Part 1 - Setup virtualenv

Part 2 - Setup Pygame

Part 3 - Start making game

Part 4 - Make a “flapping” flappy bird

Part 5 - Make the bird fly

Part 6 - Pipe System

Part 7 - Kill the Bird

Part 8 - Add game logic

Part 9 - Finalize the game

PART 2: Install pygame and start playing

At this point we are ready to start writing code. Let’s explore around to see what code to write. A quick Google search for “make game in python” shows that the most used library for making game in python is called Pygame.

With another search, I was able to find Pygame Documentation It seems to have several tutorials, which are likely to be useful to us as we write our own game.

The first step to do is to install pygame using pip:

pip install pygame

Surprisingly, and unfortunately, I got an error:

Collecting pygame
  Using cached pygame-1.9.6.tar.gz (3.2 MB)
    ERROR: Command errored out with exit status 1:
     command: /home/dieu/Github/flappybird/venv/bin/python -c 'import sys, setuptools, tokenize; sys.argv[0] = '"'"'/tmp/pip-install-nxev5sni/pygame/setup.py'"'"'; __file__='"'"'/tmp/pip-install-nxev5sni/pygame/setup.py'"'"';f=getattr(tokenize, '"'"'open'"'"', open)(__file__);code=f.read().replace('"'"'\r\n'"'"', '"'"'\n'"'"');f.close();exec(compile(code, __file__, '"'"'exec'"'"'))' egg_info --egg-base /tmp/pip-pip-egg-info-sek0qmaf
         cwd: /tmp/pip-install-nxev5sni/pygame/
    Complete output (18 lines):
    
    
    WARNING, No "Setup" File Exists, Running "buildconfig/config.py"
    Using UNIX configuration...
    
    
    Hunting dependencies...
    SDL     : found 1.2.15
    FONT    : not found
    IMAGE   : not found
    MIXER   : not found
    PNG     : found
    JPEG    : found
    SCRAP   : found
    PORTMIDI: found
    PORTTIME: found
    FREETYPE: found 23.1.17
    Missing dependencies
    ----------------------------------------
ERROR: Command errored out with exit status 1: python setup.py egg_info Check the logs for full command output.

The error log looks quite complicated, and maybe even scary, but looks like there are some dependencies that are not available in the system. As I keep looking around, I found this page in Pygame Wiki, that explains how to build pygame from scratch. While that might not be what we want, we might have to do it in the end, if nothing else works. However, this line in the instruction looks quite interesting to me:

#install dependencies
sudo apt-get install git python3-dev python3-setuptools python3-numpy python3-opengl \
    libsdl-image1.2-dev libsdl-mixer1.2-dev libsdl-ttf2.0-dev libsmpeg-dev \
    libsdl1.2-dev libportmidi-dev libswscale-dev libavformat-dev libavcodec-dev \
    libtiff5-dev libx11-6 libx11-dev fluid-soundfont-gm timgm6mb-soundfont \
    xfonts-base xfonts-100dpi xfonts-75dpi xfonts-cyrillic fontconfig fonts-freefont-ttf libfreetype6-dev

As you see in the error log above, what I seemed to be missing were FONT, IMAGE and MIXER, while among these packages we have libsdl-image1.2-dev, libsdl-mixer1.2-dev and libsdl-ttf2.0-dev. My theory is that these packages are responsible for the dependencies that we are missing.

So I tried installing those packages with sudo apt-get install and try pip install pygame again. This time it works

Collecting pygame
  Using cached pygame-1.9.6.tar.gz (3.2 MB)
Building wheels for collected packages: pygame
  Building wheel for pygame (setup.py) ... done
  Created wheel for pygame: filename=pygame-1.9.6-cp38-cp38-linux_x86_64.whl size=3832979 sha256=0eb9b839343f5c80db18d1823ab381a82171c0a95ba6ff3997ad6f0e57e7c4f2
  Stored in directory: /home/dieu/.cache/pip/wheels/5c/3a/34/864e618a7e57b5df7cc5f1d1338aa43e7d566a4749a540c9b7
Successfully built pygame
Installing collected packages: pygame
Successfully installed pygame-1.9.6

These three missing packages only work in my case, since even if you are using Ubuntu like me, you may have missed other dependencies than I did. I just want to share the debugging process here for you to see things might get ugly from time to time, even for professional devs. In fact, a large part of your job as a software developer will be to debug those random errors.

If you run into the same situation like I did, the safest choice will be to install all packages listed in the install dependencies command.

There are actually simpler method to test if the library works listed in the Wiki, but I prefer to test it with a simple example, since that example might help us understand how pygame works. Let’s try the bouncing ball tutorial in Pygame documentation to see if it works well.

Open VIM, or your favorite editor and create a file named intro.py. Pasting the complete code in the tutorial to it:

import sys, pygame
pygame.init()

size = width, height = 320, 240
speed = [2, 2]
black = 0, 0, 0

screen = pygame.display.set_mode(size)

ball = pygame.image.load("intro_ball.gif")
ballrect = ball.get_rect()

while 1:
    for event in pygame.event.get():
        if event.type == pygame.QUIT: sys.exit()

    ballrect = ballrect.move(speed)
    if ballrect.left < 0 or ballrect.right > width:
        speed[0] = -speed[0]
    if ballrect.top < 0 or ballrect.bottom > height:
        speed[1] = -speed[1]

    screen.fill(black)
    screen.blit(ball, ballrect)
    pygame.display.flip()

Notice that we have the line pygame.image.load("intro_ball.gif"), and there is an image of a ball there. When I right-clicked on the ball image and press “Save Image As…”, I could verify that the image’s name is, indeed, intro_ball.gif. So I saved it to the project’s directory:

Save this bouncing ball image

When we run python intro.py, we can see that the ball is bouncing on a black screen, so pygame works. Now press Ctrl-c to stop it. Next, we would like to play around with these few lines of code to see what they do.

while 1: is an infinite loop, so what’s running inside that block seems to be repeated infinitely. This is a normal way to make movements in games: by creating a sequence of still images, which “tricks” human brain into thinking that the image is actually “moving”. The movement is, however, so fast that it’s difficult to test this hypothesis. Let’s try adding some sleep and print lines:

import time
...
i = 0
while 1:
    print(f"Frame {i}")
    i += 1
    time.sleep(1)

So basically, we set an one-second pause in every iteration, which, if the infinite loop is triggered as we predicted, should slow down the movement to 1 frame-per-second (fps). At the same time, in the terminal window that we run the command, an indicator of frame should be printed out.

And expected, that was what we get: as the ball slowly moves, we get the frame numbers display up in the terminal window.

pygame 1.9.6
Hello from the pygame community. https://www.pygame.org/contribute.html
Frame 0
Frame 1
Frame 2
Frame 3
Frame 4
Frame 5
Frame 6
Frame 7
Frame 8

The next step is to determine if we can change the speed of the ball. This speed list looks like what we need to adjust. Right now it is [2,2], but let’s see how it goes if we change that. When we set it to [2, 0], the ball only moves horizontally, and with speed equals [0, 2] the ball moves vertically. So we know that how the move function works: it receives a list of length 2, whose first element changes the object’s horizontal and second changes its vertical position.

One thing that looks strange is the last line in the loop pygame.display.flip(). We, luckily, have a search function in the Pygame Doc (Image)

Exploit the search function in documentation

Indeed, we had no problem getting the explanation:

 pygame.display.flip()
    Update the full display Surface to the screen

As an experiment, let’s try removing that line from the code. What we get is a black box with no ball.

The rest of the code looks quite easy to understand, so for every iteration:

  • If the game receives pygame.QUIT event, it calls sys.exit(), which means quitting the program.
  • the ballrect object moves with speed, if it meets one of the screen edges, the ball’s speed changes to the opposite direction.
  • screen.fill() draws the frame’s background color.
  • screen.blit() draws the ball

So it seems that we have acquired quite a lot techniques to get closer to our Flappy Bird challenge. Let’s continue on the next post.

To see other posts in the same series, please click below:

Part 1 - Setup virtualenv

Part 2 - Setup Pygame

Part 3 - Start making game

Part 4 - Make a “flapping” flappy bird

Part 5 - Make the bird fly

Part 6 - Pipe System

Part 7 - Kill the Bird

Part 8 - Add game logic

Part 9 - Finalize the game

Written by Huy Mai