鱼C论坛

 找回密码
 立即注册
查看: 7412|回复: 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()。最后,在主逻辑中绘制背景图片。关键代码如下:
# -*- coding:utf-8 -*-
import pygame
import sys
import random
import os

class Bird(object):
        '''定义一个鸟类'''
        def __init__(self):
                '''定义初始化方法'''
                pass

        def birUpdate(self):
                pass

class Pipeline(object):
        '''定义一个管道类'''
        def __init__(self):
                '''定义初始化方法'''
                pass

        def updatePipeline(self):
                '''水平移动'''
                pass

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

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

                background = pygame.image.load('assets/background.png')        #加载背景图片
                createMap()                                                        #绘制地图
        pygame.quit()                                                        #退出
运行效果如下图:
微信截图_20191225151118.png

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

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

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

class Pipeline(object):
        '''定义一个管道类'''
        def __init__(self):
                '''定义初始化方法'''
                pass

        def updatePipeline(self):
                '''水平移动'''
                pass

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

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

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

微信截图_20191225153648.png

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

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

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

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

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

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

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

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

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

                background = pygame.image.load('assets/background.png')        #加载背景图片
                createMap()                                                        #绘制地图
        pygame.quit()                                                        #退出
上述代码中,在createMap()函数内,设置先显示管道,再显示小鸟。这样做的目的是为了当小鸟与管道图像重合时,小鸟的图像显示在上层,而管道的图像显示在底层。运行结果如下图:
QQ截图20191225155325.png

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

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

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

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

if __name__ == '__main__':
        #省略部分代码……
        while True:
        #省略部分代码……
        pygame.quit()                                                        #退出
运行效果如下图:
微信截图_20191225160902.png

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

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

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

def createMap():
        #省略部分代码……
def checkDead():
        #上方管子的矩形位置
        upRect = pygame.Rect(Pipeline.wallx,-300,
                                                 Pipeline.pineUp.get_width() - 10,
                                                 Pipeline.pineUp.get_height())
        #下方管子的矩形位置
        downRect = pygame.Rect(Pipeline.wallx,500,
                                                 Pipeline.pineDown.get_width() - 10,
                                                 Pipeline.pineDown.get_height())
        #检测小鸟与上下方管子是否碰撞
        if upRect.colliderect(Bird.birdRect) or downRect.colliderect(Bird.birdRect):
                Bird.dead = True
        #检测小鸟是否飞出上下边界
        if not 0 < Bird.birdRect[1] < height:
                Bird.dead = True
                return True
        else:
                return False

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

if __name__ == '__main__':
        #省略部分代码……
        while True:
        #省略部分代码……
                background = pygame.image.load('assets/background.png')        #加载背景图片
                if checkDead():                                                #检测小鸟生命状态
                        getResutl()                                                #如果小鸟死亡,显示游戏总分
                else:
                        createMap()                                                #绘制地图        
        pygame.quit()                                                        #退出
上述代码的checkDead()方法中,upRect.colliderect(Bird.birdRect)用于检测小鸟的矩形区域是否与上面的管道的矩形区域相撞, colliderect()函数的参数是另一个矩形区域对象。

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

评分

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

查看全部评分

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

 楼主| 发表于 2019-12-25 17:00:44 | 显示全部楼层
源代码回复可见
游客,如果您要查看本帖隐藏内容请回复
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2019-12-25 18:24:21 | 显示全部楼层
看看学习
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2020-2-12 11:17:31 From FishC Mobile | 显示全部楼层
学习一下
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2020-3-15 10:30:37 | 显示全部楼层
学习
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

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

楼主做的还不错
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2020-3-17 19:06:58 | 显示全部楼层
学习
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2020-4-11 17:36:22 | 显示全部楼层
谢谢大佬
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2020-4-11 20:26:21 | 显示全部楼层
1
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2020-4-13 17:38:02 | 显示全部楼层
学习一下
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2020-4-13 18:12:32 | 显示全部楼层
学习学习
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2020-4-13 18:16:04 | 显示全部楼层
学习学习
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2020-4-14 18:58:42 | 显示全部楼层
学习
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2020-4-14 19:21:53 From FishC Mobile | 显示全部楼层
认真学习
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2020-4-15 21:43:58 | 显示全部楼层
6
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2020-6-11 20:55:23 | 显示全部楼层
O    O
   O
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2020-6-27 10:09:48 | 显示全部楼层
真的好
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2020-7-8 09:28:25 | 显示全部楼层
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2020-7-21 18:39:30 | 显示全部楼层
谢谢
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2020-7-21 20:19:20 | 显示全部楼层
求代码
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

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

本版积分规则

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

GMT+8, 2024-11-16 07:43

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

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