音效素材网提供各类素材,打造精品素材网站!

站内导航 站长工具 投稿中心 手机访问

音效素材

pygame面向对象的飞行小鸟实现(Flappy bird)
日期:2021-09-08 13:56:33   来源:脚本之家

一些想法

自学python已经有快三个月了 最近这段时间没有怎么写过python 很多东西反而又遗忘了 准备翻以前的笔记复习一下在博客上记录下来 自己也没能够做出什么厉害的东西 小鸟游戏算是目前自己写的最好的一个代码了

基本游戏界面就是这样

在这里插入图片描述

分析需要的功能

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

  • 初始游戏菜单界面
  • 游戏进行界面
  • 游戏结束界面

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

  • 小鸟类
  • 管道类

因为是使用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] # 缺口的距离 有这6个随机距离

# 写的途中的全局变量都可以写在最上面 

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

3.游戏窗口的设置

pygame.init() # 进行初始化
SCREEN = pygame.display.set_mode((MAP_WIDTH, MAP_HEIGHT)) # 屏幕大小
pygame.display.set_caption('飞行小鸟') # 标题
CLOCK = pygame.time.Clock() 

4.加载素材
加载游戏图片和音乐

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')

5.执行函数
就是执行程序的函数

def main():
		menu_window()
    result = game_window()
    end_window(result)

6.程序入口

if __name__ == '__main__':
  main()

7.我将游戏分成了三个界面

  • 初始游戏菜单界面
  • 游戏进行界面
  • 游戏结束界面
def menu_window():
	pass

def game_window():
	pass

def end_window(result):
	pass

# 这里就是写运行三种游戏界面的代码

8.因为要显示游戏得分

所以专门写一个方法在游戏主界面代码里面直接调用这个方法 让代码不会显得冗余

9.最后就是我们游戏角色和道具的类方法

  • 小鸟类
  • 管道类
class Bird(pygame.sprite.Sprite):
  def __init__(self, x, y):
    # super(Bird, self).__init__(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] # 缺口的距离 有这6个随机距离
# PIPE_GAPS1 = []
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)]

# 将图片设置成一个大字典 里面通过key-value存不同的场景图
IMAGES = {}
IMAGES['numbers'] = [pygame.image.load(number) for number in NUMBERS] # 数字素材有10张 因此遍历
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() # 屏幕高减去floor图片的高 就是他在屏幕里的位置

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)) # random的choice方法可以随机从列表里返回一个元素 白天或者黑夜
    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)] # flip是翻转 将管道放下面和上面 Flase水平不动,True上下翻转
    SOUNDS['start'].play()
    # SOUNDS['main'].play()
    menu_window()
    result = game_window()
    end_window(result)


def menu_window():
  SOUNDS['world_clear'].play()
  floor_gap = IMAGES['floor'].get_width() - MAP_WIDTH # 地板间隙 336 - 288 = 48
  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 # 小鸟飞行的速率 按y坐标向下
  max_y_shift = 50 # 小鸟飞行的最大幅度
  y_shift = 0 # 小鸟起始幅度为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 # 刷新地板的x轴
    else:
      floor_x -= 4 # 地板 x轴的移动速度

    if abs(y_shift) == max_y_shift: # 如果y_shift的绝对值 = 最大幅度
      bird_y_vel *= -1 # 调转方向飞 同时飞行速度为1
    else:
      bird_y += bird_y_vel
    y_shift += bird_y_vel # 小鸟y轴正负交替 上下飞

    # 小鸟翅膀
    idx += 1 # 翅膀煽动频率
    idx %= len(frame_seq) # 通过取余得到 0 1 2
    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) # 以每秒30帧刷新屏幕


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

  floor_gap = IMAGES['floor'].get_width() - MAP_WIDTH # 地板间隙 336 - 288 = 48
  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) # 四舍五入取整数 屏幕宽度/两个管道之间的距离 这个距离时候刷新第二个管道 2.4
  pipe_group = pygame.sprite.Group() # 是一个集合

  # 生成前面的管道
  pipe_x = MAP_WIDTH
  pipe_y = random.randint(PIPE_HEIGHT_RANGE[0], PIPE_HEIGHT_RANGE[1]) # 管道长度随机从153.6 到 358.4
  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 # 刷新地板的x轴
    else:
      floor_x -= 4 # 地板 x轴的移动速度

    # 生成最后一个管道
    if len(pipe_group) / 2 < n_pair: # 当管道组长度<2.4 时 意思就是两个半管道的时候
      # sprites()将管道组返回成列表
      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()
    # 鸟的矩形y坐标如果大于地板的高度 就死亡
    # pygame.sprite.spritecollideany 碰撞函数 如果bird和pipe_group碰撞了 就死亡
    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的图片
  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

    # 使用类go_die方法 鸟儿撞墙后 旋转往下
    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: # IMAGES['numbers'] = [pygame.image.load(number) for number in NUMBERS]
    SCREEN.blit(IMAGES['numbers'][int(number)], (x, y))
    x += w


class Bird(pygame.sprite.Sprite):
  def __init__(self, x, y):
    # super(Bird, self).__init__(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 # 翅膀拍打往上飞 y坐标-10
    self.y_vel = -10 # y坐标的速度
    self.max_y_vel = 15 # y轴下落最大速度
    self.rotate = 0 # 脑袋朝向
    self.rotate_vel = -3 # 转向速度
    self.max_rotate = -30 # 最大转向速度
    self.flap_rotate = 45 # 按了空格只会脑袋朝向上30度

  def update(self, flap=False):
    if flap:
      self.y_vel = self.flap_acc # 拍打翅膀 则y速度-10向上
      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) # 0~20
    self.image = self.frames[self.frame_list[self.frame_index]]
    self.image = pygame.transform.rotate(self.image, self.rotate) # transform变形方法 旋转

  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
    # 利用flip方法 旋转管道成为反向管道
    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 # 管道x轴加移动速度
    if self.rect.right < 0:
      self.kill()


if __name__ == '__main__':
  main()

到此这篇关于pygame面向对象的飞行小鸟实现(Flappy bird)的文章就介绍到这了,更多相关pygame 飞行小鸟内容请搜索以前的文章或继续浏览下面的相关文章希望大家以后多多支持!

    您感兴趣的教程

    在docker中安装mysql详解

    本篇文章主要介绍了在docker中安装mysql详解,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编...

    详解 安装 docker mysql

    win10中文输入法仅在桌面显示怎么办?

    win10中文输入法仅在桌面显示怎么办?

    win10系统使用搜狗,QQ输入法只有在显示桌面的时候才出来,在使用其他程序输入框里面却只能输入字母数字,win10中...

    win10 中文输入法

    一分钟掌握linux系统目录结构

    这篇文章主要介绍了linux系统目录结构,通过结构图和多张表格了解linux系统目录结构,感兴趣的小伙伴们可以参考一...

    结构 目录 系统 linux

    PHP程序员玩转Linux系列 Linux和Windows安装

    这篇文章主要为大家详细介绍了PHP程序员玩转Linux系列文章,Linux和Windows安装nginx教程,具有一定的参考价值,感兴趣...

    玩转 程序员 安装 系列 PHP

    win10怎么安装杜比音效Doby V4.1 win10安装杜

    第四代杜比®家庭影院®技术包含了一整套协同工作的技术,让PC 发出清晰的环绕声同时第四代杜比家庭影院技术...

    win10杜比音效

    纯CSS实现iOS风格打开关闭选择框功能

    这篇文章主要介绍了纯CSS实现iOS风格打开关闭选择框,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作...

    css ios c

    Win7如何给C盘扩容 Win7系统电脑C盘扩容的办法

    Win7如何给C盘扩容 Win7系统电脑C盘扩容的

    Win7给电脑C盘扩容的办法大家知道吗?当系统分区C盘空间不足时,就需要给它扩容了,如果不管,C盘没有足够的空间...

    Win7 C盘 扩容

    百度推广竞品词的投放策略

    SEM是基于关键词搜索的营销活动。作为推广人员,我们所做的工作,就是打理成千上万的关键词,关注它们的质量度...

    百度推广 竞品词

    Visual Studio Code(vscode) git的使用教程

    这篇文章主要介绍了详解Visual Studio Code(vscode) git的使用,小编觉得挺不错的,现在分享给大家,也给大家做个参考。...

    教程 Studio Visual Code git

    七牛云储存创始人分享七牛的创立故事与

    这篇文章主要介绍了七牛云储存创始人分享七牛的创立故事与对Go语言的应用,七牛选用Go语言这门新兴的编程语言进行...

    七牛 Go语言

    Win10预览版Mobile 10547即将发布 9月19日上午

    微软副总裁Gabriel Aul的Twitter透露了 Win10 Mobile预览版10536即将发布,他表示该版本已进入内部慢速版阶段,发布时间目...

    Win10 预览版

    HTML标签meta总结,HTML5 head meta 属性整理

    移动前端开发中添加一些webkit专属的HTML5头部标签,帮助浏览器更好解析HTML代码,更好地将移动web前端页面表现出来...

    移动端html5模拟长按事件的实现方法

    这篇文章主要介绍了移动端html5模拟长按事件的实现方法的相关资料,小编觉得挺不错的,现在分享给大家,也给大家...

    移动端 html5 长按

    HTML常用meta大全(推荐)

    这篇文章主要介绍了HTML常用meta大全(推荐),文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参...

    cdr怎么把图片转换成位图? cdr图片转换为位图的教程

    cdr怎么把图片转换成位图? cdr图片转换为

    cdr怎么把图片转换成位图?cdr中插入的图片想要转换成位图,该怎么转换呢?下面我们就来看看cdr图片转换为位图的...

    cdr 图片 位图

    win10系统怎么录屏?win10系统自带录屏详细教程

    win10系统怎么录屏?win10系统自带录屏详细

    当我们是使用win10系统的时候,想要录制电脑上的画面,这时候有人会想到下个第三方软件,其实可以用电脑上的自带...

    win10 系统自带录屏 详细教程

    + 更多教程 +
    ASP编程JSP编程PHP编程.NET编程python编程