Python——pygame 面向对象的飞行小鸟(Flappy bird)

飞行小鸟(Flappy bird)

一些想法

基本游戏界面就是这样

Python——pygame 面向对象的飞行小鸟(Flappy bird)

; 分析需要的功能

我的构思是将游戏分成三个部分

  1. 初始游戏菜单界面
  2. 游戏进行界面
  3. 游戏结束界面

游戏里的角色和道具则使用类

  1. 小鸟类
  2. 管道类

因为是使用pygame模块 我对这个模块也很不熟悉 很多功能都是论坛参考其他大神的 比如

pygame.transform 里面的各种变化功能
pygame.sprite 精灵模块里面的方法

构建整体框架

  1. 导入pygame和random pygame拥有丰富的制作游戏的功能 random是随机模块 游戏里各种随机事件就是通过这个模块功能实现
import pygame
import random

2.我们写一个小的项目之前 需要将每个功能分成不同的代码块

  • 定义的变量都写到最上面
MAP_WIDTH = 288
MAP_HEIGHT = 512
FPS = 30
PIPE_GAPS = [110, 120, 130, 140, 150, 160]

全局变量我一般喜欢使用大写来区分

  1. 游戏窗口的设置
pygame.init()
SCREEN = pygame.display.set_mode((MAP_WIDTH, MAP_HEIGHT))
pygame.display.set_caption('飞行小鸟')
CLOCK = pygame.time.Clock()
  1. 加载素材
    加载游戏图片和音乐
SPRITE_FILE = './images'
IMAGES = {}
IMAGES['guide'] = pygame.image.load(SPRITE_FILE + 'guide.png')
IMAGES['gameover'] = pygame.image.load(SPRITE_FILE + 'gameover.png')
IMAGES['floor'] = pygame.image.load(SPRITE_FILE + 'floor.png')

SPRITE_SOUND = './audio/'
SOUNDS = {}
SOUNDS['start'] = pygame.mixer.Sound(SPRITE_SOUND + 'start.wav')
SOUNDS['die'] = pygame.mixer.Sound(SPRITE_SOUND + 'die.wav')
SOUNDS['hit'] = pygame.mixer.Sound(SPRITE_SOUND + 'hit.wav')
SOUNDS['score'] = pygame.mixer.Sound(SPRITE_SOUND + 'score.wav')
  1. 执行函数
    就是执行程序的函数
def main():
        menu_window()
        result = game_window()
        end_window(result)
  1. 程序入口
if __name__ == '__main__':
    main()
  1. 我将游戏分成了三个界面
  2. 初始游戏菜单界面
  3. 游戏进行界面
  4. 游戏结束界面
def menu_window():
    pass

def game_window():
    pass

def end_window(result):
    pass

  1. 因为要显示游戏得分 所以专门写一个方法在游戏主界面代码里面直接调用这个方法 让代码不会显得冗余
  2. 最后就是我们游戏角色和道具的类方法
  3. 小鸟类
  4. 管道类
class Bird(pygame.sprite.Sprite):
    def __init__(self, x, y):

        pygame.sprite.Sprite.__init__(self)
        pass

    def update(self, flap=False):
        pass

    def go_die(self):
        pass

class Pipe(pygame.sprite.Sprite):
    def __init__(self, x, y, upwards=True):
        pygame.sprite.Sprite.__init__(self)
       pass

    def update(self):
        pass

我们把整体框架搭建好之后 就可以着手完善代码

着手完整代码

"""
Project: pygame
Creator: stan Z
Create time: 2021-03-08 19:37
IDE: PyCharm
Introduction:
"""
import pygame
import random

MAP_WIDTH = 288
MAP_HEIGHT = 512
FPS = 30
PIPE_GAPS = [90, 100, 110, 120, 130, 140]

PIPE_HEIGHT_RANGE = [int(MAP_HEIGHT * 0.3), int(MAP_HEIGHT * 0.7)]
PIPE_DISTANCE = 120

pygame.init()
SCREEN = pygame.display.set_mode((MAP_WIDTH, MAP_HEIGHT))
pygame.display.set_caption('飞行小鸟byStanZ')
CLOCK = pygame.time.Clock()

SPRITE_FILE = './images'

BIRDS = [[f'{SPRITE_FILE}{bird}-{move}.png' for move in ['up', 'mid', 'down']] for bird in ['red', 'blue', 'yellow']]
BGPICS = [SPRITE_FILE + 'day.png', SPRITE_FILE + 'night.png']
PIPES = [SPRITE_FILE + 'green-pipe.png', SPRITE_FILE + 'red-pipe.png']
NUMBERS = [f'{SPRITE_FILE}{n}.png' for n in range(10)]

IMAGES = {}
IMAGES['numbers'] = [pygame.image.load(number) for number in NUMBERS]
IMAGES['guide'] = pygame.image.load(SPRITE_FILE + 'guide.png')
IMAGES['gameover'] = pygame.image.load(SPRITE_FILE + 'gameover.png')
IMAGES['floor'] = pygame.image.load(SPRITE_FILE + 'floor.png')

FLOOR_H = MAP_HEIGHT - IMAGES['floor'].get_height()

SPRITE_SOUND = './sound'
SOUNDS = {}
SOUNDS['start'] = pygame.mixer.Sound(SPRITE_SOUND + 'start.wav')
SOUNDS['die'] = pygame.mixer.Sound(SPRITE_SOUND + 'die.wav')
SOUNDS['hit'] = pygame.mixer.Sound(SPRITE_SOUND + 'hit.wav')
SOUNDS['score'] = pygame.mixer.Sound(SPRITE_SOUND + 'score.wav')
SOUNDS['flap'] = pygame.mixer.Sound(SPRITE_SOUND + 'flap.wav')
SOUNDS['death'] = pygame.mixer.Sound(SPRITE_SOUND + 'death.wav')
SOUNDS['main'] = pygame.mixer.Sound(SPRITE_SOUND + 'main_theme.ogg')
SOUNDS['world_clear'] = pygame.mixer.Sound(SPRITE_SOUND + 'world_clear.wav')

def main():
    while True:
        IMAGES['bgpic'] = pygame.image.load(random.choice(BGPICS))
        IMAGES['bird'] = [pygame.image.load(frame) for frame in random.choice(BIRDS)]
        pipe = pygame.image.load(random.choice(PIPES))
        IMAGES['pipe'] = [pipe, pygame.transform.flip(pipe, False, True)]
        SOUNDS['start'].play()

        menu_window()
        result = game_window()
        end_window(result)

def menu_window():
    SOUNDS['world_clear'].play()
    floor_gap = IMAGES['floor'].get_width() - MAP_WIDTH
    floor_x = 0

    guide_x = (MAP_WIDTH - IMAGES['guide'].get_width()) / 2
    guide_y = MAP_HEIGHT * 0.12

    bird_x = MAP_WIDTH * 0.2
    bird_y = MAP_HEIGHT * 0.5 - IMAGES['bird'][0].get_height() / 2
    bird_y_vel = 1
    max_y_shift = 50
    y_shift = 0

    idx = 0
    frame_seq = [0] * 5 + [1] * 5 + [2] * 5 + [1] * 5

    while True:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                quit()
            elif event.type == pygame.KEYDOWN and event.key == pygame.K_SPACE:
                return

        if floor_x  -floor_gap:
            floor_x = floor_x + floor_gap
        else:
            floor_x -= 4

        if abs(y_shift) == max_y_shift:
            bird_y_vel *= -1
        else:
            bird_y += bird_y_vel
        y_shift += bird_y_vel

        idx += 1
        idx %= len(frame_seq)
        frame_index = frame_seq[idx]

        SCREEN.blit(IMAGES['bgpic'], (0, 0))
        SCREEN.blit(IMAGES['floor'], (floor_x, FLOOR_H))
        SCREEN.blit(IMAGES['guide'], (guide_x, guide_y))
        SCREEN.blit(IMAGES['bird'][frame_index], (bird_x, bird_y))

        pygame.display.update()
        CLOCK.tick(FPS)

def game_window():
    SOUNDS['world_clear'].stop()
    SOUNDS['main'].play()
    score = 0

    floor_gap = IMAGES['floor'].get_width() - MAP_WIDTH
    floor_x = 0

    bird_x = MAP_WIDTH * 0.2
    bird_y = MAP_HEIGHT * 0.5 - IMAGES['bird'][0].get_height() / 2
    bird = Bird(bird_x, bird_y)

    n_pair = round(MAP_WIDTH / PIPE_DISTANCE)
    pipe_group = pygame.sprite.Group()

    pipe_x = MAP_WIDTH
    pipe_y = random.randint(PIPE_HEIGHT_RANGE[0], PIPE_HEIGHT_RANGE[1])
    pipe1 = Pipe(pipe_x, pipe_y, upwards=True)
    pipe_group.add(pipe1)
    pipe2 = Pipe(pipe_x, pipe_y - random.choice(PIPE_GAPS), upwards=False)
    pipe_group.add(pipe2)

    SOUNDS['flap'].play()

    while True:
        flap = False

        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                quit()
            elif event.type == pygame.KEYDOWN and event.key == pygame.K_SPACE:
                SOUNDS['flap'].play()
                flap = True

        bird.update(flap)

        if floor_x  -floor_gap:
            floor_x = floor_x + floor_gap
        else:
            floor_x -= 4

        if len(pipe_group) / 2 < n_pair:

            last_pipe = pipe_group.sprites()[-1]
            pipe_x = last_pipe.rect.right + PIPE_DISTANCE
            pipe_y = random.randint(PIPE_HEIGHT_RANGE[0], PIPE_HEIGHT_RANGE[1])
            pipe1 = Pipe(pipe_x, pipe_y, upwards=True)
            pipe_group.add(pipe1)
            pipe2 = Pipe(pipe_x, pipe_y - random.choice(PIPE_GAPS), upwards=False)
            pipe_group.add(pipe2)

        pipe_group.update()

        if bird.rect.y > FLOOR_H or bird.rect.y < 0 or pygame.sprite.spritecollideany(bird, pipe_group):
            SOUNDS['score'].stop()
            SOUNDS['main'].stop()
            SOUNDS['hit'].play()
            SOUNDS['die'].play()
            SOUNDS['death'].play()

            result = {'bird': bird, 'score': score, 'pipe_group': pipe_group}
            return result

        if pipe_group.sprites()[0].rect.left == 0:
            SOUNDS['score'].play()
            score += 1

        SCREEN.blit(IMAGES['bgpic'], (0, 0))
        pipe_group.draw(SCREEN)
        SCREEN.blit(IMAGES['floor'], (floor_x, FLOOR_H))
        SCREEN.blit(bird.image, bird.rect)
        show_score(score)
        pygame.display.update()
        CLOCK.tick(FPS)

def end_window(result):

    gameover_x = MAP_WIDTH * 0.5 - IMAGES['gameover'].get_width() / 2
    gameover_y = MAP_HEIGHT * 0.4
    bird = result['bird']
    pipe_group = result['pipe_group']

    while True:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                quit()
            elif event.type == pygame.KEYDOWN and event.key == pygame.K_SPACE and bird.rect.y > FLOOR_H:
                SOUNDS['death'].stop()
                return

        bird.go_die()
        SCREEN.blit(IMAGES['bgpic'], (0, 0))
        pipe_group.draw(SCREEN)
        SCREEN.blit(IMAGES['floor'], (0, FLOOR_H))
        SCREEN.blit(IMAGES['gameover'], (gameover_x, gameover_y))
        show_score(result['score'])
        SCREEN.blit(bird.image, bird.rect)
        pygame.display.update()
        CLOCK.tick(FPS)

def show_score(score):
    score_str = str(score)
    w = IMAGES['numbers'][0].get_width()
    x = MAP_WIDTH / 2 - 2 * w / 2
    y = MAP_HEIGHT * 0.1
    for number in score_str:
        SCREEN.blit(IMAGES['numbers'][int(number)], (x, y))
        x += w

class Bird(pygame.sprite.Sprite):
    def __init__(self, x, y):

        pygame.sprite.Sprite.__init__(self)
        self.frames = IMAGES['bird']
        self.frame_list = [0] * 5 + [1] * 5 + [2] * 5 + [1] * 5
        self.frame_index = 0
        self.image = self.frames[self.frame_list[self.frame_index]]
        self.rect = self.image.get_rect()
        self.rect.x = x
        self.rect.y = y
        self.gravity = 1
        self.flap_acc = -10
        self.y_vel = -10
        self.max_y_vel = 15
        self.rotate = 0
        self.rotate_vel = -3
        self.max_rotate = -30
        self.flap_rotate = 45

    def update(self, flap=False):
        if flap:
            self.y_vel = self.flap_acc
            self.rotate = self.flap_rotate
        else:
            self.rotate = self.rotate + self.rotate_vel

        self.y_vel = min(self.y_vel + self.gravity, self.max_y_vel)
        self.rect.y += self.y_vel
        self.rorate = max(self.rotate + self.rotate_vel, self.max_rotate)

        self.frame_index += 1
        self.frame_index %= len(self.frame_list)
        self.image = self.frames[self.frame_list[self.frame_index]]
        self.image = pygame.transform.rotate(self.image, self.rotate)

    def go_die(self):
        if self.rect.y < FLOOR_H:
            self.y_vel = self.max_y_vel
            self.rect.y += self.y_vel
            self.rotate = -90
            self.image = self.frames[self.frame_list[self.frame_index]]
            self.image = pygame.transform.rotate(self.image, self.rotate)

class Pipe(pygame.sprite.Sprite):
    def __init__(self, x, y, upwards=True):
        pygame.sprite.Sprite.__init__(self)
        self.x_vel = -4

        if upwards:
            self.image = IMAGES['pipe'][0]
            self.rect = self.image.get_rect()
            self.rect.x = x
            self.rect.top = y

        else:
            self.image = IMAGES['pipe'][1]
            self.rect = self.image.get_rect()
            self.rect.x = x
            self.rect.bottom = y

    def update(self):
        self.rect.x += self.x_vel
        if self.rect.right < 0:
            self.kill()

if __name__ == '__main__':
    main()

我把每行复杂的代码都写了注释

Original: https://blog.csdn.net/Cantevenl/article/details/115278806
Author: stan Z
Title: Python——pygame 面向对象的飞行小鸟(Flappy bird)

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/780549/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球