How to program python game “Flappy bird” on CrowPi

Tony   2018/12/14   How to program python game “Flappy bird” on CrowPi已关闭评论

Last week, my niece came over and picked up the phone to show me the flappy bird game she played. But a few minutes later, her mother took the phone away, then she was a heartbreaking cry and rolled on the ground. When I looked at her watery eyes, as her uncle, I thought of a plan – use Python to program the “Flappy bird” game on CrowPi to save my niece.

Her mother won’t let her play the phone because she thinks that the phone will only affect her learning and let her indulge in the virtual world of the Internet. Therefor , CrowPi must be a wonderful choice. CrowPi is based on learning and entertainment. It allows users to learn while playing, in order to stimulate users’ interest in learning, so as to maximize the user’s commitment to learning. CrowPi’s controller is the latest version of the Raspberry Pi 3 Model B+, thanks to the powerful features of the Raspberry Pi, which allows users to do almost anything on the CrowPi that can be done on a computer. In addition, It is not only equipped with 7 inch HD touchscreen along with a camera, but it also has a lot of cool learning modules, such as digital tube, ultrasonic sensor, lcd display, led matrix, etc. even have a breadboard on the user To build your own circuit, the most important thing is that it looks so beautiful! So I took one for myself.

122-1

Let’s talk about this game first. Flappy Bird is easy to operate. Click on the screen to make Bird rise, score through the column obstacles, and hit the game. Because of the height of obstacles, controlling the rise and fall of Bird requires quick and flexible response, and it is not easy to get a higher score.


We need to analyze this game before programming. This game is roughly divided into 4 parts:

1, background

2, bird

3, pipe

4, menu, start and end screen, score, etc.

In these four parts, our main analysis is birds and pipes.


The bird will always fly to the right, and will drop if you don’t click the screen.Every time you click on the screen, the bird will make the upward flight. When you don’t click the screen, the bird is down.
Pipe will have two colors randomly appearing and one direction up and down, it will appear constantly and each time a pipe will add a point.
The game will end when the bird hits the pipe or falls to the ground.


Gossip less, we hurry to start our programming!
Let’s start with a brief modular introduction, and finally the full code will be given. First of all, I think it is also the most important to import our library files.

from itertools import cycle

import random

import sys

import pygame      #Import the pygame library into a python program

from pygame.locals import *      #Need to introduce all the constants in pygame

Then I will define some variables, such as the size of the screen and FPS(control how often each loop runs). And some array to store image, sound, hitmask.

FPS = 30

SCREENWIDTH  = 288 #Screen width

SCREENHEIGHT = 512 #Screen height

IMAGES, SOUNDS, HITMASKS = {}, {}, {}

In the main() function, I will add some image, sound and how to load  background and player sprites and so on.

IMAGES[‘numbers’] = (

        pygame.image.load(‘assets/sprites/0.png’).convert_alpha(),

        pygame.image.load(‘assets/sprites/1.png’).convert_alpha(),

        pygame.image.load(‘assets/sprites/2.png’).convert_alpha(),

        pygame.image.load(‘assets/sprites/3.png’).convert_alpha(),

        pygame.image.load(‘assets/sprites/4.png’).convert_alpha(),

        pygame.image.load(‘assets/sprites/5.png’).convert_alpha(),

        pygame.image.load(‘assets/sprites/6.png’).convert_alpha(),

        pygame.image.load(‘assets/sprites/7.png’).convert_alpha(),

        pygame.image.load(‘assets/sprites/8.png’).convert_alpha(),

        pygame.image.load(‘assets/sprites/9.png’).convert_alpha()

    )


SOUNDS[‘die’]    = pygame.mixer.Sound(‘assets/audio/die’ + soundExt)

SOUNDS[‘hit’]    = pygame.mixer.Sound(‘assets/audio/hit’ + soundExt)

SOUNDS[‘point’]  = pygame.mixer.Sound(‘assets/audio/point’ + soundExt)

SOUNDS[‘swoosh’] = pygame.mixer.Sound(‘assets/audio/swoosh’ + soundExt)

SOUNDS[‘wing’]   = pygame.mixer.Sound(‘assets/audio/wing’ + soundExt)

The next step is to generate random, although the environment is still the environment, but the background is different, the birds are different, and the pipeline is random.

while True:

        # select random background sprites  

        randBg = random.randint(0, len(BACKGROUNDS_LIST) – 1)        #Randomly choose 0 or 1

        IMAGES[‘background’] =                                                                                                  pygame.image.load(BACKGROUNDS_LIST[randBg]).convert()        #Load random background

        # select random player sprites 

        randPlayer = random.randint(0, len(PLAYERS_LIST) – 1)

        IMAGES[‘player’] = (

            pygame.image.load(PLAYERS_LIST[randPlayer][0]).convert_alpha(),

            pygame.image.load(PLAYERS_LIST[randPlayer][1]).convert_alpha(),

            pygame.image.load(PLAYERS_LIST[randPlayer][2]).convert_alpha(),

        )

        # select random pipe sprites 

        pipeindex = random.randint(0, len(PIPES_LIST) – 1)

        IMAGES[‘pipe’] = (

            pygame.transform.rotate(

                pygame.image.load(PIPES_LIST[pipeindex]).convert_alpha(), 180),   #Rotate 180 degrees

            pygame.image.load(PIPES_LIST[pipeindex]).convert_alpha(),

        )               #One above the pipe one below the one pipe

        # hismask for pipes 

        HITMASKS[‘pipe’] = (

            getHitmask(IMAGES[‘pipe’][0]),

            getHitmask(IMAGES[‘pipe’][1]),

        )

        # hitmask for player 

        HITMASKS[‘player’] = (

            getHitmask(IMAGES[‘player’][0]),

            getHitmask(IMAGES[‘player’][1]),

            getHitmask(IMAGES[‘player’][2]),

        )

        movementInfo = showWelcomeAnimation()     #Return ‘playery’ (player location), ‘basex’ (base image location) ‘playerIndexGen’ (flight posture index)

        crashInfo = mainGame(movementInfo)

        showGameOverScreen(crashInfo)

The above has already prepared the materials to be used in the game, then we have to start setting up the game screen.First, in the showWelcomeAnimation() function,I will make some decoration for the game. As everyone knows, a good looking game welcome interface is very eye-catching and important. And what I want to emphasize the pygame.event() event handler, which handles keyboard or mouse events with ease.

 for event in pygame.event.get():       #Use pygame.event.get() to handle all events

            #If quit or press esc after pressing the button, the game ends

            if event.type == QUIT or (event.type == KEYDOWN and event.key == K_ESCAPE):         

                pygame.quit()

                sys.exit()

            #If you click or press after pressing the button

            if event.type == KEYDOWN and (event.key == K_SPACE or event.key == K_UP)):    

                # make first flap sound and return values for mainGame

                SOUNDS[‘wing’].play()       #Play the special effects sound of the fly

                return {

                    #Return to the initial position Enter maingame

                    ‘playery’: playery + playerShmVals[‘val’],

                    ‘basex’: basex,

                    ‘playerIndexGen’: playerIndexGen,

                }

20170914161640072

The mainGame() function is arguably the most important part of this game code. In this function, you need to define the starting attitude of the flight, the pipe, the character’s character speed, the maximum speed, the downward acceleration, etc., and also the effect of each click flight or the end of the game.

score = playerIndex = loopIter = 0

playerIndexGen = movementInfo



        for event in pygame.event.get():

            if event.type == QUIT or (event.type == KEYDOWN and event.key == K_ESCAPE):

                pygame.quit()

                sys.exit()

            if event.type == KEYDOWN and (event.key == K_SPACE or event.key == K_UP ):

                if playery > -2 * IMAGES[‘player’][0].get_height():      #if click

                    playerVelY = playerFlapAcc          #Up

                    playerFlapped = True

                    SOUNDS[‘wing’].play()       #And play the flight sound

        # check for crash here

        crashTest = checkCrash({‘x’: playerx, ‘y’: playery, ‘index’: playerIndex},




for uPipe, lPipe in zip(upperPipes, lowerPipes):

            uPipe[‘x’] += pipeVelX       #pipe move

            lPipe[‘x’] += pipeVelX

2.1

 

Next we need to move the “tube”. What we want to achieve is to add a new tube to the right when the first tube is about to touch the left side, and then remove the tube when the left tube disappears. At the same time, when you pass the pipe, you must print out the score and realize the accumulation.

        for uPipe, lPipe in zip(upperPipes, lowerPipes):

            uPipe[‘x’] += pipeVelX           #pipe move

            lPipe[‘x’] += pipeVelX

        # add new pipe when first pipe is about to touch left of screen

        if 0 < upperPipes[0][‘x’] < 5:         #Generate the next pipe when the first pipe moves to the left edge of the screen

            newPipe = getRandomPipe()

            upperPipes.append(newPipe[0])

            lowerPipes.append(newPipe[1])

        # remove first pipe if its out of the screen

        if upperPipes[0][‘x’] < -IMAGES[‘pipe’][0].get_width(): 

            upperPipes.pop(0)

            lowerPipes.pop(0)

        # draw sprites

        SCREEN.blit(IMAGES[‘background’], (0,0))

        for uPipe, lPipe in zip(upperPipes, lowerPipes):

            SCREEN.blit(IMAGES[‘pipe’][0], (uPipe[‘x’], uPipe[‘y’]))

            SCREEN.blit(IMAGES[‘pipe’][1], (lPipe[‘x’], lPipe[‘y’]))

        SCREEN.blit(IMAGES[‘base’], (basex, BASEY))

        # print score so player overlaps the score

        showScore(score) 

        # Player rotation has a threshold

        visibleRot = playerRotThr

        if playerRot <= playerRotThr:

            visibleRot = playerRot

        

        playerSurface = pygame.transform.rotate(IMAGES[‘player’][playerIndex], visibleRot)        #Rotating character

        SCREEN.blit(playerSurface, (playerx, playery))         #Show rotated characters

        pygame.display.update()        #Update window

        FPSCLOCK.tick(FPS)           #How long should the loop run

The showGameOverScreen() function is to crashes the player down and shows gameover image, also including sound effects at the end of the game, screens, and keyboard event handling.

    # play hit and die sounds

    SOUNDS[‘hit’].play()

    if not crashInfo[‘groundCrash’]:       #If  haven’t hit the ground,  play the die sound.

        SOUNDS[‘die’].play()

    while True:

        for event in pygame.event.get():

            if event.type == QUIT or (event.type == KEYDOWN and event.key == K_ESCAPE):

                pygame.quit()

                sys.exit()

            if event.type == KEYDOWN and (event.key == K_SPACE or event.key == K_UP):

                if playery + playerHeight >= BASEY – 1:

                    return

20170914161647780

And the next important thing is the checkCrash() function, which is mainly to detect whether the bird collides with the ground or the tube, and if so, returns true.

    # if player crashes into ground 

    if player[‘y’] + player[‘h’] >= BASEY – 1:

        return [True, True] 

    else:

        playerRect = pygame.Rect(player[‘x’], player[‘y’],

                      player[‘w’], player[‘h’])

        pipeW = IMAGES[‘pipe’][0].get_width()

        pipeH = IMAGES[‘pipe’][0].get_height()

        for uPipe, lPipe in zip(upperPipes, lowerPipes):

            # upper and lower pipe rects

            uPipeRect = pygame.Rect(uPipe[‘x’], uPipe[‘y’], pipeW, pipeH)

            lPipeRect = pygame.Rect(lPipe[‘x’], lPipe[‘y’], pipeW, pipeH)

            # player and upper/lower pipe hitmasks

            pHitMask = HITMASKS[‘player’][pi]

            uHitmask = HITMASKS[‘pipe’][0]

            lHitmask = HITMASKS[‘pipe’][1]

            # if bird collided with upipe or lpipe

            uCollide = pixelCollision(playerRect, uPipeRect, pHitMask, uHitmask)

            lCollide = pixelCollision(playerRect, lPipeRect, pHitMask, lHitmask)

            if uCollide or lCollide:

                return [True, False]

The above is the main part of the game. Below is the complete game code I gave. The code comments are very detailed. Keep in mind that the image and sound information is found and added by yourself, otherwise it will not work. If you can’t find pictures and sound materials, you can download the falppy bird apk file online and all the materials in the internal file are available. If you have Crowpi and you want to control the game by the sensor, please see my next blog–“Control Flappy bird by sensor on Crowpi “. Ok, let’s start your game making.


from itertools import cycle import random import sys

import pygame         #Import the pygame library into a python program from pygame.locals import *         #Need to introduce all the constants in pygame

FPS=30

SCREENWIDTH  = 288 #Screen width

SCREENHEIGHT = 512 #Screen height

# amount by which base can maximum shift to left

PIPEGAPSIZE  = 100 # gap between upper and lower part of pipe 

BASEY        = SCREENHEIGHT * 0.79 #The height of the base is the height of the point, the upper left corner is the coordinate starting point, so the height is down.


IMAGES, SOUNDS, HITMASKS = {}, {}, {}
      # image, sound and hitmask  dicts


# list of all possible players (tuple of 3 positions of flap)

PLAYERS_LIST = (

    # red bird

    (

        ‘assets/sprites/redbird-upflap.png’,

        ‘assets/sprites/redbird-midflap.png’,

        ‘assets/sprites/redbird-downflap.png’,

    ),

    # blue bird

    (

        # amount by which base can maximum shift to left

        ‘assets/sprites/bluebird-upflap.png’,

        ‘assets/sprites/bluebird-midflap.png’,

        ‘assets/sprites/bluebird-downflap.png’,

    ),

    # yellow bird

    (

        ‘assets/sprites/yellowbird-upflap.png’,

        ‘assets/sprites/yellowbird-midflap.png’,

        ‘assets/sprites/yellowbird-downflap.png’,

    ),

)



# list of backgrounds 

BACKGROUNDS_LIST = (

    ‘assets/sprites/background-day.png’,

    ‘assets/sprites/background-night.png’,

)



# list of pipes 

PIPES_LIST = (

    ‘assets/sprites/pipe-green.png’,

    ‘assets/sprites/pipe-red.png’,

)


try:

    xrange

except NameError:

    xrange = range



def main():

    global SCREEN, FPSCLOCK

    pygame.init()    #After initialization, we can use pygame to the fullest


    #Before using the Pygame clock, you must first create an instance of the Clock object.

    FPSCLOCK = pygame.time.Clock()      #Control how often each loop runs. It’s like a timer in the control time process, pointing out “Now start the next loop”! Start the next cycle now!


    SCREEN = pygame.display.set_mode((SCREENWIDTH, SCREENHEIGHT))     #

Usually we need to create a window to facilitate our interaction with the program.    pygame.display.set_caption(‘Flappy Bird’)      #Set window title


    #Load and convert images

    #In pygame you can use pygame.image.load() function to load bitmaps (support jpg, png, gif, bmp, pcx, tif, tga and other image formats).

    #The convert_alpha() method will use a transparent method to draw the foreground object。

    # Therefore, when loading a material with an alpha channel (such as PNG TGA), you need to use the convert_alpha() method. Of course, ordinary images can also use this method. There is no side effect.

    IMAGES[‘numbers’] = (

        pygame.image.load(‘assets/sprites/0.png’).convert_alpha(),

        pygame.image.load(‘assets/sprites/1.png’).convert_alpha(),

        pygame.image.load(‘assets/sprites/2.png’).convert_alpha(),

        pygame.image.load(‘assets/sprites/3.png’).convert_alpha(),

        pygame.image.load(‘assets/sprites/4.png’).convert_alpha(),

        pygame.image.load(‘assets/sprites/5.png’).convert_alpha(),

        pygame.image.load(‘assets/sprites/6.png’).convert_alpha(),

        pygame.image.load(‘assets/sprites/7.png’).convert_alpha(),

        pygame.image.load(‘assets/sprites/8.png’).convert_alpha(),

        pygame.image.load(‘assets/sprites/9.png’).convert_alpha()

    )


# game over sprite

IMAGES[‘gameover’] = pygame.image.load(‘assets/sprites/gameover.png’).convert_alpha()

# message sprite for welcome screen

IMAGES[‘message’] = pygame.image.load(‘assets/sprites/message.png’).convert_alpha()

# base (ground) sprite

IMAGES[‘base’] = pygame.image.load(‘assets/sprites/base.png’).convert_alpha()

# sounds

# WAV OGG version refers to the audio format of the game

# WAV version belongs to the original game

# OGG is that the WAV of the audio format is changed to OGG by the converter, so that the configuration of the game is increased, and the size of the game itself is reduced to save space.

# can look at the same audio ogg version is much smaller than the wav version of the file

if ‘win’ in sys.platform:        #Determine the current system platform to set the sound file suffix

        soundExt = ‘.wav’

else:

        soundExt = ‘.ogg’

# Sound effects: pygame.mixer

# Sound = pygame.mixer.Sound(‘/home/liumin/love.wav’) Loads an audio file with the specified filename and creates a Sound object. Audio files can be in wav, ogg and other formats.

# The contents of the audio file will be fully loaded into the memory.

SOUNDS[‘die’]    = pygame.mixer.Sound(‘assets/audio/die’ + soundExt)

SOUNDS[‘hit’]    = pygame.mixer.Sound(‘assets/audio/hit’ + soundExt)

SOUNDS[‘point’]  = pygame.mixer.Sound(‘assets/audio/point’ + soundExt)

SOUNDS[‘swoosh’] = pygame.mixer.Sound(‘assets/audio/swoosh’ + soundExt)

SOUNDS[‘wing’]   = pygame.mixer.Sound(‘assets/audio/wing’ + soundExt)

 while True:

        # select random background sprites  

        randBg = random.randint(0, len(BACKGROUNDS_LIST) – 1)        #Randomly choose 0 or 1

        IMAGES[‘background’] =                                                                                                  pygame.image.load(BACKGROUNDS_LIST[randBg]).convert()        #Load random background

        # select random player sprites 

        randPlayer = random.randint(0, len(PLAYERS_LIST) – 1)

        IMAGES[‘player’] = (

            pygame.image.load(PLAYERS_LIST[randPlayer][0]).convert_alpha(),

            pygame.image.load(PLAYERS_LIST[randPlayer][1]).convert_alpha(),

            pygame.image.load(PLAYERS_LIST[randPlayer][2]).convert_alpha(),

        )

        # select random pipe sprites 

        pipeindex = random.randint(0, len(PIPES_LIST) – 1)

        IMAGES[‘pipe’] = (

            pygame.transform.rotate(

                pygame.image.load(PIPES_LIST[pipeindex]).convert_alpha(), 180),   #Rotate 180 degrees

            pygame.image.load(PIPES_LIST[pipeindex]).convert_alpha(),

        )               #One above the pipe one below the one pipe

        # hismask for pipes 

        HITMASKS[‘pipe’] = (

            getHitmask(IMAGES[‘pipe’][0]),

            getHitmask(IMAGES[‘pipe’][1]),

        )

        # hitmask for player 

        HITMASKS[‘player’] = (

            getHitmask(IMAGES[‘player’][0]),

            getHitmask(IMAGES[‘player’][1]),

            getHitmask(IMAGES[‘player’][2]),

        )

        movementInfo = showWelcomeAnimation()     #Return ‘playery’ (player location), ‘basex’ (base image location) ‘playerIndexGen’ (flight posture index)

        crashInfo = mainGame(movementInfo)

        showGameOverScreen(crashInfo)

def showWelcomeAnimation():

    “””Shows welcome screen animation of flappy bird”””

    # Index of player to blit on screen

    playerIndex = 0

    playerIndexGen = cycle([0, 1, 2, 1])

    # iterator used to change playerIndex after every 5th iteration

    loopIter = 0

    #Player location

    playerx = int(SCREENWIDTH * 0.2)

    playery = int((SCREENHEIGHT – IMAGES[‘player’][0].get_height()) / 2)

    #Welcome image location

    messagex = int((SCREENWIDTH – IMAGES[‘message’].get_width()) / 2)

    messagey = int(SCREENHEIGHT * 0.12)

    basex = 0

    # amount by which base can maximum shift to left 

    baseShift = IMAGES[‘base’].get_width() – IMAGES[‘background’].get_width()

    # player shm for up-down motion on welcome screen 

    playerShmVals = {‘val’: 0, ‘dir’: 1}

    while True:

        for event in pygame.event.get():       #Use pygame.event.get() to handle all events

            if event.type == QUIT or (event.type == KEYDOWN and event.key == K_ESCAPE):        #If quit or press esc after pressing the button, the game ends

                pygame.quit()

                sys.exit()

            if event.type == KEYDOWN and (event.key == K_SPACE or event.key == K_UP )):      #If you click or press after pressing the button

                # make first flap sound and return values for mainGame

                SOUNDS[‘wing’].play()       #Play the special effects sound of the fly

                return {

                    #Return to the initial position Enter maingame

                    ‘playery’: playery + playerShmVals[‘val’],

                    ‘basex’: basex,

                    ‘playerIndexGen’: playerIndexGen,

                }

        # adjust playery, playerIndex, basex

        if (loopIter + 1) % 5 == 0:

            playerIndex = next(playerIndexGen)      #Get the sibling elements next to each element in the set of matching elements. Adjust the flight pose picture.

        loopIter = (loopIter + 1) % 30

        basex = -((-basex + 4) % baseShift)

        playerShm(playerShmVals)

        # draw sprites

        #screen.blit(space, (0,0))can draw a bitmap. The first parameter is the bitmap that is loaded and the second parameter is the starting coordinates of the drawing.

        SCREEN.blit(IMAGES[‘background’], (0,0))

        SCREEN.blit(IMAGES[‘player’][playerIndex],

                    (playerx, playery + playerShmVals[‘val’]))

        SCREEN.blit(IMAGES[‘message’], (messagex, messagey))

        SCREEN.blit(IMAGES[‘base’], (basex, BASEY))

        pygame.display.update()      #Update entire window

        FPSCLOCK.tick(FPS)              #How long should the loop run

def mainGame(movementInfo):

    score = playerIndex = loopIter = 0        #The initial score and the initial player’s pose and the number of iterations are 0.

    playerIndexGen = movementInfo[‘playerIndexGen’]     #Get flight posture

    playerx, playery = int(SCREENWIDTH * 0.2), movementInfo[‘playery’]      #player location

    basex = movementInfo[‘basex’]          #base image location

    baseShift = IMAGES[‘base’].get_width() – IMAGES[‘background’].get_width()

    # get 2 new pipes to add to upperPipes lowerPipes list

    newPipe1 = getRandomPipe()

    newPipe2 = getRandomPipe()

    # list of upper pipes

    upperPipes = [

        {‘x’: SCREENWIDTH + 200, ‘y’: newPipe1[0][‘y’]},

        {‘x’: SCREENWIDTH + 200 + (SCREENWIDTH / 2), ‘y’: newPipe2[0][‘y’]},

    ]

    # list of lowerpipe

    lowerPipes = [

        {‘x’: SCREENWIDTH + 200, ‘y’: newPipe1[1][‘y’]},

        {‘x’: SCREENWIDTH + 200 + (SCREENWIDTH / 2), ‘y’: newPipe2[1][‘y’]},

    ]

    pipeVelX = -4

    # player velocity, max velocity, downward accleration, accleration on flap 

    playerVelY    =  -9   # player’s velocity along Y, default same as playerFlapped

    playerMaxVelY =  10   # max vel along Y, max descend speed

    playerMinVelY =  -8   # min vel along Y, max ascend speed

    playerAccY    =   1   # players downward accleration

    playerRot     =  45   # player’s rotation

    playerVelRot  =   3   # angular speed

    playerRotThr  =  20   # rotation threshold

    playerFlapAcc =  -9   # players speed on flapping

    playerFlapped = False # True when player flaps

    while True:

        for event in pygame.event.get():

            if event.type == QUIT or (event.type == KEYDOWN and event.key == K_ESCAPE):

                pygame.quit()

                sys.exit()

            if event.type == KEYDOWN and (event.key == K_SPACE or event.key == K_UP ):

                if playery > -2 * IMAGES[‘player’][0].get_height():      #if click

                    playerVelY = playerFlapAcc          #Up

                    playerFlapped = True

                    SOUNDS[‘wing’].play()       #And play the flight sound

        # check for crash here

        crashTest = checkCrash({‘x’: playerx, ‘y’: playery, ‘index’: playerIndex},

                               upperPipes, lowerPipes)

        if crashTest[0]:             #if falls to the ground or hits the pipe,then return to the end of the game

            return {

                ‘y’: playery,

                ‘groundCrash’: crashTest[1],

                ‘basex’: basex,

                ‘upperPipes’: upperPipes,

                ‘lowerPipes’: lowerPipes,

                ‘score’: score,

                ‘playerVelY’: playerVelY,

                ‘playerRot’: playerRot

            }

        # check for score

        playerMidPos = playerx + IMAGES[‘player’][0].get_width() / 2

        for pipe in upperPipes:

            pipeMidPos = pipe[‘x’] + IMAGES[‘pipe’][0].get_width() / 2

            if pipeMidPos <= playerMidPos < pipeMidPos + 4:     #When the character reaches the middle of the pipe gap +4, score+1, and play the score sound at this time

                score += 1

                SOUNDS[‘point’].play()

        # playerIndex basex change

        if (loopIter + 1) % 3 == 0:

            playerIndex = next(playerIndexGen)

        loopIter = (loopIter + 1) % 30

        basex = -((-basex + 100) % baseShift)

        # rotate the player

        if playerRot > -90:

            playerRot -= playerVelRot

        # player’s movement

        if playerVelY < playerMaxVelY and not playerFlapped:

            playerVelY += playerAccY

        if playerFlapped:

            playerFlapped = False

            # more rotation to cover the threshold (calculated in visible rotation)

            playerRot = 45

        playerHeight = IMAGES[‘player’][playerIndex].get_height()

        playery += min(playerVelY, BASEY – playery – playerHeight)

        # move pipes to left

        for uPipe, lPipe in zip(upperPipes, lowerPipes):

            uPipe[‘x’] += pipeVelX           #pipe move

            lPipe[‘x’] += pipeVelX

        # add new pipe when first pipe is about to touch left of screen

        if 0 < upperPipes[0][‘x’] < 5:         #Generate the next pipe when the first pipe moves to the left edge of the screen

            newPipe = getRandomPipe()

            upperPipes.append(newPipe[0])

            lowerPipes.append(newPipe[1])

        # remove first pipe if its out of the screen

        if upperPipes[0][‘x’] < -IMAGES[‘pipe’][0].get_width(): 

            upperPipes.pop(0)

            lowerPipes.pop(0)

        # draw sprites

        SCREEN.blit(IMAGES[‘background’], (0,0))

        for uPipe, lPipe in zip(upperPipes, lowerPipes):

            SCREEN.blit(IMAGES[‘pipe’][0], (uPipe[‘x’], uPipe[‘y’]))

            SCREEN.blit(IMAGES[‘pipe’][1], (lPipe[‘x’], lPipe[‘y’]))

        SCREEN.blit(IMAGES[‘base’], (basex, BASEY))

        # print score so player overlaps the score

        showScore(score) 

        # Player rotation has a threshold

        visibleRot = playerRotThr

        if playerRot <= playerRotThr:

            visibleRot = playerRot

        

        playerSurface = pygame.transform.rotate(IMAGES[‘player’][playerIndex], visibleRot)        #Rotating character

        SCREEN.blit(playerSurface, (playerx, playery))         #Show rotated characters

        pygame.display.update()        #Update window

        FPSCLOCK.tick(FPS)           #How long should the loop run

def showGameOverScreen(crashInfo):

    “””crashes the player down ans shows gameover image”””

    score = crashInfo[‘score’]       #Get the score

    playerx = SCREENWIDTH * 0.2

    playery = crashInfo[‘y’]

    playerHeight = IMAGES[‘player’][0].get_height()

    playerVelY = crashInfo[‘playerVelY’]

    playerAccY = 2

    playerRot = crashInfo[‘playerRot’]

    playerVelRot = 7

    basex = crashInfo[‘basex’]

    upperPipes, lowerPipes = crashInfo[‘upperPipes’], crashInfo[‘lowerPipes’]

    # play hit and die sounds

    SOUNDS[‘hit’].play()

    if not crashInfo[‘groundCrash’]:       #If  haven’t hit the ground,  play the die sound.

        SOUNDS[‘die’].play()

    while True:

        for event in pygame.event.get():

            if event.type == QUIT or (event.type == KEYDOWN and event.key == K_ESCAPE):

                pygame.quit()

                sys.exit()

            if event.type == KEYDOWN and (event.key == K_SPACE or event.key == K_UP):

                if playery + playerHeight >= BASEY – 1:

                    return

        # player y shift

        if playery + playerHeight < BASEY – 1:

            playery += min(playerVelY, BASEY – playery – playerHeight)

        # player velocity change

        if playerVelY < 15:

            playerVelY += playerAccY

        # rotate only when it’s a pipe crash

        if not crashInfo[‘groundCrash’]:

            if playerRot > -90:

                playerRot -= playerVelRot

        # draw sprites

        SCREEN.blit(IMAGES[‘background’], (0,0))

        for uPipe, lPipe in zip(upperPipes, lowerPipes):

            SCREEN.blit(IMAGES[‘pipe’][0], (uPipe[‘x’], uPipe[‘y’]))

            SCREEN.blit(IMAGES[‘pipe’][1], (lPipe[‘x’], lPipe[‘y’]))

        SCREEN.blit(IMAGES[‘base’], (basex, BASEY))

        showScore(score)

        playerSurface = pygame.transform.rotate(IMAGES[‘player’][1], playerRot)

        SCREEN.blit(playerSurface, (playerx,playery))

        FPSCLOCK.tick(FPS)

        pygame.display.update()

def playerShm(playerShm):

    “””oscillates the value of playerShm[‘val’] between 8 and -8″””

    if abs(playerShm[‘val’]) == 8:

        playerShm[‘dir’] *= -1

    if playerShm[‘dir’] == 1:

         playerShm[‘val’] += 1

    else:

        playerShm[‘val’] -= 1

def getRandomPipe():      

    “””returns a randomly generated pipe”””

    # y of gap between upper and lower pipe

    gapY = random.randrange(0, int(BASEY * 0.6 – PIPEGAPSIZE))

    gapY += int(BASEY * 0.2)

    pipeHeight = IMAGES[‘pipe’][0].get_height()

    pipeX = SCREENWIDTH + 10

    return [

        {‘x’: pipeX, ‘y’: gapY – pipeHeight},  # upper pipe

        {‘x’: pipeX, ‘y’: gapY + PIPEGAPSIZE}, # lower pipe

    ]

def showScore(score):

    “””displays score in center of screen”””

    scoreDigits = [int(x) for x in list(str(score))]

    totalWidth = 0 # total width of all numbers to be printed

    for digit in scoreDigits:

        totalWidth += IMAGES[‘numbers’][digit].get_width()

    Xoffset = (SCREENWIDTH – totalWidth) / 2

    for digit in scoreDigits:

        SCREEN.blit(IMAGES[‘numbers’][digit], (Xoffset, SCREENHEIGHT * 0.1))    #display score

        Xoffset += IMAGES[‘numbers’][digit].get_width()

def checkCrash(player, upperPipes, lowerPipes):

    “””returns True if player collders with base or pipes.”””

    pi = player[‘index’]       #Flight posture

    player[‘w’] = IMAGES[‘player’][0].get_width()

    player[‘h’] = IMAGES[‘player’][0].get_height()

    # if player crashes into ground 

    if player[‘y’] + player[‘h’] >= BASEY – 1:

        return [True, True] 

    else:

        playerRect = pygame.Rect(player[‘x’], player[‘y’],

                      player[‘w’], player[‘h’])

        pipeW = IMAGES[‘pipe’][0].get_width()

        pipeH = IMAGES[‘pipe’][0].get_height()

        for uPipe, lPipe in zip(upperPipes, lowerPipes):

            # upper and lower pipe rects

            uPipeRect = pygame.Rect(uPipe[‘x’], uPipe[‘y’], pipeW, pipeH)

            lPipeRect = pygame.Rect(lPipe[‘x’], lPipe[‘y’], pipeW, pipeH)

            # player and upper/lower pipe hitmasks

            pHitMask = HITMASKS[‘player’][pi]

            uHitmask = HITMASKS[‘pipe’][0]

            lHitmask = HITMASKS[‘pipe’][1]

            # if bird collided with upipe or lpipe

            uCollide = pixelCollision(playerRect, uPipeRect, pHitMask, uHitmask)

            lCollide = pixelCollision(playerRect, lPipeRect, pHitMask, lHitmask)

            if uCollide or lCollide:

                return [True, False]

    return [False, False]

def pixelCollision(rect1, rect2, hitmask1, hitmask2):

    “””Checks if two objects collide and not just their rects”””

    rect = rect1.clip(rect2)        #Coincidence between roles and pipes

    if rect.width == 0 or rect.height == 0:         #Didn’t coincide, it didn’t hit

        return False

    x1, y1 = rect.x – rect1.x, rect.y – rect1.y

    x2, y2 = rect.x – rect2.x, rect.y – rect2.y

    for x in xrange(rect.width):

        for y in xrange(rect.height):

            if hitmask1[x1+x][y1+y] and hitmask2[x2+x][y2+y]:         #Hit it 

                return True

    return False

def getHitmask(image):

    “””returns a hitmask using an image’s alpha.”””

    #Get the impact mask

    mask = []

    for x in xrange(image.get_width()):

        mask.append([])

        for y in xrange(image.get_height()):

            mask[x].append(bool(image.get_at((x,y))[3]))

    return mask

if __name__ == ‘__main__’:

    main()