鱼C论坛

 找回密码
 立即注册
查看: 8394|回复: 35

[作品展示] 使用Pygame模块制作Flappy Bird游戏

[复制链接]
发表于 2019-12-25 16:43:50 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
本帖最后由 xenli 于 2019-12-25 16:46 编辑

源代码在二楼
1、游戏简介
        Flappy Bird 是一款鸟类 飞行游戏,由越南河内独立游戏开发者阮哈东(Dong Nguyen)开发。在        Flappy Bird这款游戏中,玩家只需要用一根手指来操控,单击触摸手机屏幕,小鸟就会往上飞。不断地单击屏幕,小鸟就会不断地往高处飞;放松手指,则会快速下降。玩家要控制小鸟一直向前飞行,并且注意躲避途中高低不平的管子。如果小鸟碰到了障碍物,游戏就会结束。每当小鸟飞过一组管道,玩家就会获得1分。

成品效果
16.gif

2、游戏分析
        在Flappy Bird游戏中,主要有两个对象:小鸟和管道。可以创建Bird类和Pineline类来分别表示这两个对象。小鸟可以通过上下移动来躲避管道,所以在Bird类中创建一个birdUpdate()方法,实现小鸟的上下移动。为了体现小鸟向前飞行的特征,可以让管道一直向左侧移动,这样在窗口中就好像小鸟在向前飞行。所以,在Pineline类中也创建一个updatePipeline()方法,实现管道的向左移动。此外,还创建了3个函数:createMap()函数用于绘制地图;checkDead()函数用于判断小鸟的生命状态;getResult()函数用于获取最终分数。最后在主逻辑中,实例化类并调用相关方法,实现相应功能。

3、搭建主框架
        通过前面的分析,我们可以搭建起Flappy Bird游戏的主框架。Flappy Bird游戏有两个对象:小鸟和管道。先来创建这两个类,类中具体的方法可以先使用pass语句代替。然后创建一个绘制地图的函数createMap()。最后,在主逻辑中绘制背景图片。关键代码如下:
  1. # -*- coding:utf-8 -*-
  2. import pygame
  3. import sys
  4. import random
  5. import os

  6. class Bird(object):
  7.         '''定义一个鸟类'''
  8.         def __init__(self):
  9.                 '''定义初始化方法'''
  10.                 pass

  11.         def birUpdate(self):
  12.                 pass

  13. class Pipeline(object):
  14.         '''定义一个管道类'''
  15.         def __init__(self):
  16.                 '''定义初始化方法'''
  17.                 pass

  18.         def updatePipeline(self):
  19.                 '''水平移动'''
  20.                 pass

  21. def createMap():
  22.         '''定义创建地图的方法'''
  23.         screen.fill((255,255,255))                        #填充颜色
  24.         screen.blit(background,(0,0))                #填入到背景
  25.         pygame.display.update()                                #更新显示

  26. if __name__ == '__main__':
  27.         pygame.init()                                                        #初始化pygame
  28.         os.environ["SDL_VIDEO_WINDOW_POS"] = "%d, %d" % (800, 200)  
  29.         size = width,height = 400,650                        #设置窗口
  30.         screen = pygame.display.set_mode(size)        #显示窗口
  31.         clock = pygame.time.Clock()                                #设置时钟
  32.         Pipeline = Pipeline()                                        #实例化管道类
  33.         Bird = Bird()                                                        #实例化鸟类
  34.         while True:
  35.                 clock.tick(50)                                                #每秒执行50次
  36.                 # 轮询事件
  37.                 for event in pygame.event.get():
  38.                         if event.type == pygame.QUIT:
  39.                                 sys.exit()

  40.                 background = pygame.image.load('assets/background.png')        #加载背景图片
  41.                 createMap()                                                        #绘制地图
  42.         pygame.quit()                                                        #退出
复制代码

运行效果如下图:
微信截图_20191225151118.png

4、创建小鸟类
        下面来创建小鸟类。该类需要初始化很多参数,所以定义一个__init__() 方法,用来初始化各种参数,包括鸟飞行的几种状态、飞行的速度、跳跃的高度等。然后定义birdUpdate()方法,该方法用于实现小鸟的跳跃和坠落。接下来,在主逻辑的轮询事件中添加键盘按下事件或鼠标单击事件,如按下鼠标,使小鸟上升等。最后,在createMap()方法中,显示小鸟的图像。关键代码如下:
  1. # -*- coding:utf-8 -*-
  2. import pygame
  3. import sys
  4. import random
  5. import os

  6. class Bird(object):
  7.         '''定义一个鸟类'''
  8.         def __init__(self):
  9.                 '''定义初始化方法'''
  10.                 self.birdRect = pygame.Rect(65,50,50,50)        #鸟的矩形
  11.                 # 定义鸟的3种状态列表
  12.                 self.birdStatus = [pygame.image.load('assets/1.png'),
  13.                                                         pygame.image.load('assets/2.png'),
  14.                                                         pygame.image.load('assets/dead.png')]
  15.                 self.status = 0                        #默认飞行状态
  16.                 self.birdX = 120                #鸟所在的X轴坐标,即是向右飞行的速度
  17.                 self.birdY = 350                #鸟所在的Y轴坐标,即是上下飞行的高度
  18.                 self.jump = False                #默认情况小鸟自动降落
  19.                 self.jumpSpeed = 10          #跳跃高度
  20.                 self.gravity = 5                 #重力
  21.                 self.dead = False                #默认小鸟生命状态为活着

  22.         def birUpdate(self):
  23.                 if self.jump:
  24.                         #小鸟跳跃
  25.                         self.jumpSpeed -= 1        #速度递减,上升越来越慢
  26.                         self.birdY -= self.jumpSpeed        #鸟的Y轴坐标减少,小鸟上升
  27.                 else:
  28.                         #小鸟坠落
  29.                         self.gravity += 0.2                                 #重力递增,下降越来越快
  30.                         self.birdY += self.gravity                #鸟的Y轴坐标增加,小鸟下降
  31.                 self.birdRect[1] = self.birdY                #更改Y轴位置

  32. class Pipeline(object):
  33.         '''定义一个管道类'''
  34.         def __init__(self):
  35.                 '''定义初始化方法'''
  36.                 pass

  37.         def updatePipeline(self):
  38.                 '''水平移动'''
  39.                 pass

  40. def createMap():
  41.         '''定义创建地图的方法'''
  42.         screen.fill((255,255,255))                        #填充颜色
  43.         screen.blit(background,(0,0))                #填入到背景
  44.         #显示小鸟
  45.         if Bird.dead:                                                #撞管道状态
  46.                 Bird.status = 2
  47.         elif Bird.jump:                                                #起飞状态
  48.                 Bird.status = 1
  49.         screen.blit(Bird.birdStatus[Bird.status],(Bird.birdX,Bird.birdY))        #设置小鸟的坐标
  50.         Bird.birUpdate()                                        #鸟移动
  51.         pygame.display.update()                                #更新显示

  52. if __name__ == '__main__':
  53.         '''主程序'''
  54.         pygame.init()                                                        #初始化pygame
  55.         os.environ["SDL_VIDEO_WINDOW_POS"] = "%d, %d" % (800, 200)  
  56.         size = width,height = 400,650                        #设置窗口
  57.         screen = pygame.display.set_mode(size)        #显示窗口
  58.         clock = pygame.time.Clock()                                #设置时钟
  59.         Pipeline = Pipeline()                                        #实例化管道类
  60.         Bird = Bird()                                                        #实例化鸟类
  61.         while True:
  62.                 clock.tick(50)                                                #每秒执行50次
  63.                 # 轮询事件
  64.                 for event in pygame.event.get():
  65.                         if event.type == pygame.QUIT:
  66.                                 sys.exit()
  67.                         if (event.type == pygame.KEYDOWN or event.type == pygame.MOUSEBUTTONDOWN) and not Bird.dead:
  68.                                 Bird.jump = True                        #跳跃
  69.                                 Bird.gravity = 5                                #重力
  70.                                 Bird.jumpSpeed = 10                        #跳跃速度

  71.                 background = pygame.image.load('assets/background.png')        #加载背景图片
  72.                 createMap()                                                        #绘制地图
  73.         pygame.quit()
复制代码

上述代码在Bird类中设置了birdStatus 属性,该属性是一个鸟类图片的列表,列表中显示鸟类3种飞行状态,根据小鸟的不同状态加载相应的图片。在birdUpdate()方法中,为了达到较好的动画效果,使jumpSpeed 和gravity两个属性逐渐变化。运行上述代码,在窗体内创建一只小鸟, 默认情况小鸟会一直下降。当单击一下鼠标或按一下键盘, 小鸟会跳跃一下,高度上升。运行效果如下图所示。

微信截图_20191225153648.png

5、创建管道类
创建完鸟类后,接下来创建管道类。同样,在__init__()方法中初始化各种参数,包括设置管道的坐标,加载上下管道图片等。然后在updatePipeline()方法中,定义管道向左移动的速度,并且当管道移出屏幕时,重新绘制下一组管道。最后,在createMap()函数中显示管道。关键代码如下:
  1. # -*- coding:utf-8 -*-
  2. import pygame
  3. import sys
  4. import random
  5. import os

  6. class Bird(object):
  7.         #省略部分代码……

  8. class Pipeline(object):
  9.         '''定义一个管道类'''
  10.         def __init__(self):
  11.                 '''定义初始化方法'''
  12.                 self.wallx = 400                        #管道所在X轴坐标
  13.                 self.pineUp = pygame.image.load('assets/top.png')                #加载上管道图片
  14.                 self.pineDown = pygame.image.load('assets/bottom.png')        #加载下管道图片

  15.         def updatePipeline(self):
  16.                 '''管道移动方法'''
  17.                 self.wallx -= 5                                 #管道X轴坐标递减,即管道向左移动
  18.                 # 当管道运行到一定位置,即小鸟飞跃管道,分数+1,并且重置管道
  19.                 if self.wallx < -80:
  20.                         self.wallx = 400

  21. def createMap():
  22.         '''定义创建地图的方法'''
  23.         screen.fill((255,255,255))                        #填充颜色
  24.         screen.blit(background,(0,0))                #填入到背景

  25.         #显示管道
  26.         screen.blit(Pipeline.pineUp,(Pipeline.wallx,-300))        #上管道坐标位置
  27.         screen.blit(Pipeline.pineDown,(Pipeline.wallx,500))        #下管道坐标位置
  28.         Pipeline.updatePipeline()                        #管道移动

  29.         #显示小鸟
  30.         if Bird.dead:                                                #撞管道状态
  31.                 Bird.status = 2
  32.         elif Bird.jump:                                                #起飞状态
  33.                 Bird.status = 1
  34.         screen.blit(Bird.birdStatus[Bird.status],(Bird.birdX,Bird.birdY))        #设置小鸟的坐标
  35.         Bird.birUpdate()                                        #鸟移动

  36.         pygame.display.update()                                #更新显示

  37. if __name__ == '__main__':
  38.         #省略部分代码……
  39.         while True:
  40.                 clock.tick(50)                                                #每秒执行50次
  41.                 # 轮询事件
  42.                 for event in pygame.event.get():
  43.                         if event.type == pygame.QUIT:
  44.                                 sys.exit()
  45.                         if (event.type == pygame.KEYDOWN or event.type == pygame.MOUSEBUTTONDOWN) and not Bird.dead:
  46.                                 Bird.jump = True                        #跳跃
  47.                                 Bird.gravity = 5                        #重力
  48.                                 Bird.jumpSpeed = 10                        #跳跃速度

  49.                 background = pygame.image.load('assets/background.png')        #加载背景图片
  50.                 createMap()                                                        #绘制地图
  51.         pygame.quit()                                                        #退出
复制代码

上述代码中,在createMap()函数内,设置先显示管道,再显示小鸟。这样做的目的是为了当小鸟与管道图像重合时,小鸟的图像显示在上层,而管道的图像显示在底层。运行结果如下图:
QQ截图20191225155325.png

6、计算得分
当小鸟飞过管道时,玩家得分+1.这里对于飞过管道的逻辑做了简化处理:当管道移动到窗体左侧一定距离后,默认为小鸟飞过管道,使分数+1,并显示在屏幕上。在updatePipeline()方法中已经实现该功能,关键代码如下:
  1. # -*- coding:utf-8 -*-
  2. import pygame
  3. import sys
  4. import random
  5. import os

  6. class Bird(object):
  7.         #省略部分代码……

  8. class Pipeline(object):
  9.         #省略部分代码……
  10.         def updatePipeline(self):
  11.                 '''管道移动方法'''
  12.                 self.wallx -= 5                                 #管道X轴坐标递减,即管道向左移动
  13.                 # 当管道运行到一定位置,即小鸟飞跃管道,分数+1,并且重置管道
  14.                 if self.wallx < -80:
  15.                         global score
  16.                         score += 1
  17.                         self.wallx = 400

  18. def createMap():
  19.         #省略部分代码……
  20.         #显示分数
  21.         screen.blit(font.render('Score:'+str(score),-1,(255,255,255)),(100,50)) #设置颜色及坐标位置
  22.         pygame.display.update()                                #更新显示

  23. if __name__ == '__main__':
  24.         #省略部分代码……
  25.         while True:
  26.         #省略部分代码……
  27.         pygame.quit()                                                        #退出
复制代码

运行效果如下图:
微信截图_20191225160902.png

7、碰撞检测
当小鸟与管道相撞时,小鸟颜色变为灰色,游戏结束,并且显示总分数。在checkDead()函数中通过pygame.Rect()可以分别获取小鸟的矩形区域对象和管道的矩形区域对象,该对象有一 个onlliderect()方法可以判断两个矩形区域是否相撞。如果相撞,设置Bird.dead属性为True。 此外,当小鸟飞出窗体时,也设置Bird.dead属性为True。 最后,用两行文字显示游戏得分。关键代码如下:
  1. # -*- coding:utf-8 -*-
  2. import pygame
  3. import sys
  4. import random
  5. import os

  6. class Bird(object):
  7.         #省略部分代码……

  8. class Pipeline(object):
  9.         #省略部分代码……

  10. def createMap():
  11.         #省略部分代码……
  12. def checkDead():
  13.         #上方管子的矩形位置
  14.         upRect = pygame.Rect(Pipeline.wallx,-300,
  15.                                                  Pipeline.pineUp.get_width() - 10,
  16.                                                  Pipeline.pineUp.get_height())
  17.         #下方管子的矩形位置
  18.         downRect = pygame.Rect(Pipeline.wallx,500,
  19.                                                  Pipeline.pineDown.get_width() - 10,
  20.                                                  Pipeline.pineDown.get_height())
  21.         #检测小鸟与上下方管子是否碰撞
  22.         if upRect.colliderect(Bird.birdRect) or downRect.colliderect(Bird.birdRect):
  23.                 Bird.dead = True
  24.         #检测小鸟是否飞出上下边界
  25.         if not 0 < Bird.birdRect[1] < height:
  26.                 Bird.dead = True
  27.                 return True
  28.         else:
  29.                 return False

  30. def getResutl():
  31.         final_text1 = 'Game Over'
  32.         final_text2 = 'Your final score is ' + str(score)
  33.         ft1_font = pygame.font.SysFont('Arial',70)                        #设置第一行文字字体
  34.         ft1_surf = font.render(final_text1,1,(242,3,36))        #设置第一行文字颜色
  35.         ft2_font = pygame.font.SysFont('Arial',50)                        #设置第二行文字字体
  36.         ft2_surf = font.render(final_text2,1,(253,177,6))        #设置第二行文字颜色        
  37.         #设置第一行文字显示位置
  38.         screen.blit(ft1_surf,[screen.get_width()/2 - ft1_surf.get_width()/2,100])
  39.         #设置第二行文字显示位置
  40.         screen.blit(ft2_surf,[screen.get_width()/2 - ft2_surf.get_width()/2,200])        
  41.         pygame.display.flip()                        #更新整个待显示的Surface对象到屏幕上

  42. if __name__ == '__main__':
  43.         #省略部分代码……
  44.         while True:
  45.         #省略部分代码……
  46.                 background = pygame.image.load('assets/background.png')        #加载背景图片
  47.                 if checkDead():                                                #检测小鸟生命状态
  48.                         getResutl()                                                #如果小鸟死亡,显示游戏总分
  49.                 else:
  50.                         createMap()                                                #绘制地图        
  51.         pygame.quit()                                                        #退出
复制代码

上述代码的checkDead()方法中,upRect.colliderect(Bird.birdRect)用于检测小鸟的矩形区域是否与上面的管道的矩形区域相撞, colliderect()函数的参数是另一个矩形区域对象。

说明:本实例已经实现了Flappy Bird游戏的基本功能,但还有很多需要完善的地方,如设置游戏的难度,包括设置管道的高度、小鸟的飞行速度等,各位鱼油可以尝试完善该游戏。

评分

参与人数 1荣誉 +6 鱼币 +6 贡献 +6 收起 理由
不二如是 + 6 + 6 + 6 鱼C有你更精彩^_^

查看全部评分

小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

 楼主| 发表于 2019-12-25 17:00:44 | 显示全部楼层
源代码回复可见
游客,如果您要查看本帖隐藏内容请回复
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2019-12-25 18:24:21 | 显示全部楼层
看看学习
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2020-2-12 11:17:31 From FishC Mobile | 显示全部楼层
学习一下
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2020-3-15 10:30:37 | 显示全部楼层
学习
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

发表于 2020-3-16 16:56:26 | 显示全部楼层
本帖最后由 123飞龙在天321 于 2020-3-16 16:58 编辑

楼主做的还不错
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2020-3-17 19:06:58 | 显示全部楼层
学习
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

发表于 2020-4-11 17:36:22 | 显示全部楼层
谢谢大佬
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2020-4-11 20:26:21 | 显示全部楼层
1
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

发表于 2020-4-13 17:38:02 | 显示全部楼层
学习一下
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2020-4-13 18:12:32 | 显示全部楼层
学习学习
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2020-4-13 18:16:04 | 显示全部楼层
学习学习
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2020-4-14 18:58:42 | 显示全部楼层
学习
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

发表于 2020-4-14 19:21:53 From FishC Mobile | 显示全部楼层
认真学习
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2020-4-15 21:43:58 | 显示全部楼层
6
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

发表于 2020-6-11 20:55:23 | 显示全部楼层
O    O
   O
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2020-6-27 10:09:48 | 显示全部楼层
真的好
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2020-7-8 09:28:25 | 显示全部楼层
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

发表于 2020-7-21 18:39:30 | 显示全部楼层
谢谢
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

发表于 2020-7-21 20:19:20 | 显示全部楼层
求代码
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2025-4-25 00:17

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表