还记得前几年很火那款飞飞飞之小鸟吃太胖你不点它就飞不动的游戏吗?

没错,《flappy bird》是一款由来自越南的独立游戏开发者Dong Nguyen所开发的作品,游戏于2013年5月24日上线,并在2014年2月突然暴红。

游戏玩法非常简单,通过点击屏幕,使小鸟一直飞并穿过水管的空隙。虽然玩法简单,但是却具有一定的难度,因为要一直控制小鸟飞在适合的高度,以避开障碍。

这篇文章呢,就来分析这个游戏的原理,以及用python做一个简易版的FlappyBird。当然,简易版的只是用来帮助初学者理解游戏原理,想要完整版带游戏资源的源码,文末放上Github链接。

下边开始分析游戏原理:

游戏画布

二维的游戏画布就是一个二维的坐标系,pygame游戏画布中,原点坐标(0,0)在左上角, 后边用(x, y)表示,水平方向往右x增大,垂直往下y增大,每一个坐标代表一个像素宽度。

游戏组成

游戏元素有小鸟、管道、背景。背景我们先不谈,先谈小鸟和管道。

小鸟和管道,可以是拥有不同宽高的矩形,然后根据宽高,把它们画在画布中合适的位置。设置定时器,定时更新小鸟和管道的坐标,然后重新绘制小鸟和管道,以用更新画布来模拟动画效果。

小鸟飞的原理

小鸟的x值不改变,只在垂直方向上更改y值,小鸟往上飞,y值减小,往下降落,y值增大。

不做任何操作的情况下小鸟下落,下落速度越来越快,也就是小鸟坐标y值越来越大。点击屏幕,小鸟上升,上升速度越来越慢,直到上升速度为0,小鸟开始下落。

通过更改管道的x坐标。初始管道坐标在屏幕右侧生成,减少管道的x坐标值,管道模拟往左移动,来模拟小鸟往前飞的效果。

管道空隙该如何做?

管道分为一上一下为一组,在画布中就是上下两个矩形,往左移动时,同时改变两个矩形的x值,使其x值保持一致。定义好中间的空隙的高度H,更改上下两个矩形的高度,来造成管道错落放置的效果。

下边开始写代码导入pygame和定义全局变量

#!/usr/bin/env python3

# -*- coding: utf-8 -*-

import sys

import random

import pygame

# FPS

FPS = 30

# 屏幕宽高

SCREEN_WIDTH = 288

SCREEN_HEIGHT = 512

# 管道宽高

PIPE_WIDTH = 50

PIPE_HEIGHT = 300

# 管道之间空隙

PIPE_GAP_SIZE = 100

# 小鸟

BIRD_WIDTH = 20

BIRD_HEIGHT = 20

# 地面高度

FLOOR_HEIGHT = 80

# 游戏有效高度

BASE_HEIGHT = SCREEN_HEIGHT - FLOOR_HEIGHT

2. 小鸟类

class Bird(pygame.sprite.Sprite):

def __init__(self, position):

pygame.sprite.Sprite.__init__(self)

self.rect = pygame.Rect(*position, BIRD_WIDTH, BIRD_HEIGHT)

# 定义飞行变量

self.is_flapped = False

self.up_speed = 10

self.down_speed = 0

self.time_pass = FPS / 1000

# 更新小鸟的位置

def update(self):

# 判断小鸟是上升还是下降

if self.is_flapped:

# 上升速度越来越小

self.up_speed -= 60 * self.time_pass

self.rect.top -= self.up_speed

# 上升速度小于等于0, 改为下降状态

if self.up_speed <= 0:

self.down()

self.up_speed = 10

self.down_speed = 0

else:

# 下降速度越来越大

self.down_speed += 30 * self.time_pass

self.rect.bottom += self.down_speed

# 判断小鸟是否撞到了边界死亡

is_dead = False

if self.rect.top <= 0: # 上边界

self.up_speed = 0

self.rect.top = 0

is_dead = True

if self.rect.bottom >= BASE_HEIGHT: # 下边界

self.up_speed = 0

self.down_speed = 0

self.rect.bottom = BASE_HEIGHT

is_dead = True

return is_dead

# 下落状态

def down(self):

self.is_flapped = False

# 上升状态

def up(self):

if self.is_flapped:

self.up_speed = max(12, self.up_speed + 1)

else:

self.is_flapped = True

def draw(self, screen):

pygame.draw.rect(screen, (255, 255, 255), self.rect, 1)

小鸟类继承自pygame.sprite.Sprite 的精灵类,使小鸟变成游戏中的精灵可以自由飞翔。类中定义了小鸟的 rect 属性,精灵拥有宽高和坐标,left, top 即小鸟这个矩形的左上角在画布中的坐标值。

update方法更新小鸟的位置,判断小鸟是否撞到了上下边界。如果小鸟是上升状态,上升速度随着时间而减小,小鸟top值越来越小即为往上飞,上升速度减小至0,切换为下降状态,如果是下降状态,增大小鸟的bottom值即为往下降落。

3. 管道类

class Pipe(pygame.sprite.Sprite):

def __init__(self, position):

pygame.sprite.Sprite.__init__(self)

left, top = position

# 如果是下边的管道, 通过定义管道高度, 删除地面以下的管道

pipe_height = PIPE_HEIGHT

if top > 0:

pipe_height = BASE_HEIGHT - top + 1

self.rect = pygame.Rect(left, top, PIPE_WIDTH, pipe_height)

# 用于计算分数

self.used_for_score = False

def draw(self, screen):

pygame.draw.rect(screen, (255, 255, 255), self.rect, 1)

@staticmethod

def generate_pipe_position():

# 生成上下两个管道的坐标

top = int(BASE_HEIGHT * 0.2) + random.randrange(

0, int(BASE_HEIGHT * 0.6 - PIPE_GAP_SIZE))

return {

'top': (SCREEN_WIDTH + 25, top - PIPE_HEIGHT),

'bottom': (SCREEN_WIDTH + 25, top + PIPE_GAP_SIZE)

}

管道类同样继承自pygame.sprite.Sprite。类中定义了管道的rect属性,用来在画布中渲染管道。类中还定义了一个静态方法,生成一组管道的上下两个的left值和top值。

4. 初始化游戏和精灵

# 初始化游戏

def init_game():

pygame.init()

screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))

pygame.display.set_caption('Flappy Bird')

return screen

# 初始化精灵

def init_sprite():

# 小鸟类

bird_position = [SCREEN_WIDTH * 0.2, (SCREEN_HEIGHT - BIRD_HEIGHT) / 3]

bird = Bird(bird_position)

# 管道类

pipe_sprites = pygame.sprite.Group()

for i in range(2):

pipe_pos = Pipe.generate_pipe_position()

# 添加上方的管道

pipe_sprites.add(

Pipe((SCREEN_WIDTH + i * SCREEN_WIDTH / 2,

pipe_pos.get('top')[-1])))

# 添加下方的管道

pipe_sprites.add(

Pipe((SCREEN_WIDTH + i * SCREEN_WIDTH / 2,

pipe_pos.get('bottom')[-1])))

return bird, pipe_sprites

5. 移动管道和碰撞检测

# 精灵类碰撞检测和小鸟更新位置

def collision(bird, pipe_sprites):

# 检测碰撞

is_collision = False

for pipe in pipe_sprites:

if pygame.sprite.collide_rect(bird, pipe):

is_collision = True

# 更新小鸟

is_dead = bird.update()

if is_dead:

is_collision = True

return is_collision

# 移动pipe实现小鸟往前飞的效果

def move_pipe(bird, pipe_sprites, is_add_pipe, score):

flag = False # 下一次是否要增加新的pipe的标志位

for pipe in pipe_sprites:

pipe.rect.left -= 4

# 小鸟飞过pipe 加分

if pipe.rect.centerx < bird.rect.centerx and not pipe.used_for_score:

pipe.used_for_score = True

score += 0.5

# 增加新的pipe

if pipe.rect.left < 10 and pipe.rect.left > 0 and is_add_pipe:

pipe_pos = Pipe.generate_pipe_position()

pipe_sprites.add(Pipe(position=pipe_pos.get('top')))

pipe_sprites.add(Pipe(position=pipe_pos.get('bottom')))

is_add_pipe = False

# 删除已不在屏幕的pipe, 更新标志位

elif pipe.rect.right < 0:

pipe_sprites.remove(pipe)

flag = True

if flag:

is_add_pipe = True

return is_add_pipe, score

碰撞检测直接调用pygame中的 pygame.sprite.collide_rect 方法,该方法中的两个精灵必须有rect属性。

6.画分数,画游戏结束,监控pygame事件

# 画分数

def draw_score(screen, score):

font_size = 32

digits = len(str(int(score)))

offset = (SCREEN_WIDTH - digits * font_size) / 2

font = pygame.font.SysFont('Blod', font_size)

screen.blit(font.render(str(int(score)), True, (255, 255, 255)),

(offset, SCREEN_HEIGHT * 0.1))

# 画Game Over

def draw_game_over(screen, text):

font_size = 24

font = pygame.font.SysFont('arial', font_size)

screen.blit(font.render(text, True, (255, 255, 255), (0, 0, 0)),

(60, SCREEN_HEIGHT * 0.4))

# 按键

def press(is_game_running, bird):

for event in pygame.event.get():

if event.type == pygame.QUIT: # 点击关闭按钮退出

pygame.quit()

sys.exit()

elif event.type == pygame.KEYDOWN:

if event.key == pygame.K_SPACE or event.key == pygame.K_UP: # 空格键或者up键小鸟上升

if is_game_running:

bird.up()

elif event.key == 13 and not is_game_running: # 游戏结束时回车键继续

return True

7. 主函数

def main():

screen = init_game() # 初始化游戏

bird, pipe_sprites = init_sprite() # 初始化精灵

clock = pygame.time.Clock()

is_add_pipe = True # 是否需要增加管道

is_game_running = True # 是否在游戏中

score = 0 # 初始分数

while True:

restart = press(is_game_running, bird) # 按键

if restart:

return

screen.fill((0, 0, 0)) # 填充背景

is_collision = collision(bird, pipe_sprites) # 碰撞检测

if is_collision:

is_game_running = False # 如果碰撞 游戏结束

if is_game_running:

is_add_pipe, score = move_pipe(bird, pipe_sprites, is_add_pipe,

score) # 不碰撞 移动管道

else:

draw_game_over(screen, 'Press Enter To Start!') # 游戏结束

bird.draw(screen) # 画鸟

draw_score(screen, score) # 画分数

# 画地面

pygame.draw.line(screen, (255, 255, 255), (0, BASE_HEIGHT),

(SCREEN_WIDTH, BASE_HEIGHT))

# 画管道

for pipe in pipe_sprites:

pipe.draw(screen)

# 更新画布

pygame.display.update()

clock.tick(FPS)

if __name__ == "__main__":

while True:

main()

运行效果

完整版带资源地址https://github.com/CharlesPikachu/Games/tree/master/Game6​github.com

文中源码:打代码的shy:用python写游戏系列​github.com

初来乍到,请多关照。

python 管道游戏_用python写游戏之 Flappy Bird相关推荐

  1. python抽奖游戏_利用Python写一个抽奖程序,解密游戏内抽奖的秘密

    原标题:利用Python写一个抽奖程序,解密游戏内抽奖的秘密 前言 本文的文字及图片来源于网络,仅供学习.交流使用,不具有任何商业用途,版权归原作者所有,如有问题请及时联系我们以作处理. 作者: 极客 ...

  2. python用户界面游戏_用Python和Pygame写游戏-从入门到精通(实战二:恶搞俄罗斯方块2)...

    我们接着来做这个整死人不偿命的俄罗斯方块. 代码组织和名词约定 上一次我们稍微整理了一下游戏运行的框架,这里需要整理一下python代码的框架,一个典型的pygame脚本结构如下: 其中,lib为py ...

  3. 弟子规python编程游戏_《Python游戏趣味编程》 第11章 消灭星星

    知乎视频​www.zhihu.com 图书简介可以看这里: 童晶:<Python游戏趣味编程>新书上架了​zhuanlan.zhihu.com 消灭星星是一款非常容易上瘾的消除类游戏,只需 ...

  4. python 管道队列_关于python:Multiprocessing-管道与队列

    Python的多处理程序包中的队列和管道之间的根本区别是什么? 在什么情况下应该选择一种? 什么时候使用Pipe()有优势? 什么时候使用Queue()有优势? Pipe()只能有两个端点. Queu ...

  5. python 图像识别游戏_基于Python的浏览器图像识别

    我想实现一个软件在21点计算卡,使用一些图像识别自动化的过程.但我不知道从哪里开始. 我认为问题可以分为以下几个步骤: 1-在游戏中从浏览器中获取图像(基本上是一个Adobe Flash游戏) 2-处 ...

  6. python html5游戏_【Python】Python制作塔防小游戏

    开发工具 Python版本:3.6.4 相关模块: pygame模块: 以及一些Python自带的模块. 相关文件 原理介绍 游戏规则简介: 玩家通过建造箭塔抵御敌人的进攻. 每隔一段时间,将会有一波 ...

  7. python 时间序列预测_使用Python进行动手时间序列预测

    python 时间序列预测 Time series analysis is the endeavor of extracting meaningful summary and statistical ...

  8. python 概率分布模型_使用python的概率模型进行公司估值

    python 概率分布模型 Note from Towards Data Science's editors: While we allow independent authors to publis ...

  9. 视频教程-Python小游戏-宇宙激战-Python

    Python小游戏-宇宙激战 计算机应用专业研究生硕士,教学10余年,现关注于移动互联网.大数据和人工智能研究方向. 朱松 ¥12.00 立即订阅 扫码下载「CSDN程序员学院APP」,1000+技术 ...

  10. 【源码+图片素材+详细教程】Java游戏开发_Java开发经典游戏飞翔的小鸟_飞扬的小鸟_Java游戏项目Flappy Bird像素鸟游戏_Java课程设计项目

    课程目标: 1.通过本课程的学习巩固Java的相关基础知识,例如循环判断,数组和集合的使用,对象的继承,接口的实现,窗口的创建,事件监听,图形绘制. 2.完成小鸟的移动,管道自动生成.碰撞死亡,计分系 ...

最新文章

  1. Dojo学习13 dijit.Tree 动态添加节点之一
  2. mysql 行自动增量为23,Mysql Innodb:自动增量非主键
  3. js给php注册网页添加实时监听,js 实现watch监听数据变化的代码
  4. c#使用System.Windows.Forms.DataVisualization.Charting.dll绘制图表实例
  5. java逆序对距离之和,七天刷完剑指offer-【第27道-第37道】
  6. promise async await
  7. min-max 容斥
  8. 微信扫码支付模式二【无法回调】解决方案(转)
  9. 钉钉人脸识别,戴个太阳帽就找不到人脸
  10. Atitit 扩大个人影响力和宣传目录1. 发文舆论阵地 11.1. 简书 知乎 csdn等 11.2. Ifttt出发同步 11.3. 问答平台 知乎 quaro 11.4. Tik
  11. Learun,一款专注于业务,不用写代码的框架
  12. 在线分析丨相关性分析——RDA/CCA分析
  13. 提供一个在Selenium截网页长图的实现
  14. 关于PAT报错:warning: ignoring return value of ‘scanf’, declared with attribute warn_unused_result
  15. 算法第二节:逆推法解决“银行存款问题
  16. 2010年搜索引擎的发展状况
  17. idea maven无法从私服下载jar和plugin
  18. SQL Server 练习题(初学)
  19. 常用可以下载书的网站
  20. SQL语句中except是怎样用的?

热门文章

  1. redis 应用场景
  2. 如何帮银行保持长期竞争力?融360天机公布独家秘诀
  3. Easypanel linux离线安装,easypanel
  4. 两个三维图像互信息python_含有两个数字的词语
  5. 关于使用RedisTemplate在主从架构下使用Lettuce的情况下如何实现读写分离
  6. 中普审计系统无法连接服务器,中普审计信息系统内审版-简单操作说明大全.doc...
  7. 大道至简——软件工程实践者的思想知识导图
  8. mysql的填充因子_数据库SQL Server – 索引 – 填充因子
  9. 数据库中索引原理及填充因子
  10. 安卓第三方ROM----AOKP和CM