前言

本文的文字及图片来源于网络,仅供学习、交流使用,不具有任何商业用途,如有问题请及时联系我们以作处理。

谷歌流量器中有个很有名的彩蛋:当你网络出现问题时,就会出现一个“小恐龙游戏”。

(如果想要直接进行游戏,可以在地址栏输入:chrome://dino)

今天我们就来给大家演示下,用Python来自己做一个仿制的“小恐龙游戏”!

废话不多说,让我们愉快地开始吧~

开发工具:

Python版本:3.6.4

相关模块:

pygame模块;以及一些python自带的模块。

环境搭建

安装Python并添加到环境变量,pip安装需要的相关模块即可。

先睹为快

在终端运行如下命令即可:

python Game7.py

效果如下:

代码介绍

这里介绍一下游戏的实现原理。

首先,我们对游戏进行一些必要的初始化工作:

# 游戏初始化

pygame.init()

screen = pygame.display.set_mode(cfg.SCREENSIZE)

pygame.display.set_caption('T-Rex Rush —— Charles的皮卡丘')

# 导入所有声音文件

sounds = {}

for key, value in cfg.AUDIO_PATHS.items():

sounds[key] = pygame.mixer.Sound(value)

接着,我们来考虑一下,游戏中有哪些游戏元素:

小恐龙:由玩家控制以躲避路上的障碍物;

路面:游戏的背景;

云:游戏的背景;

飞龙:路上的障碍物之一,小恐龙碰上就会死掉;

仙人掌:路上的障碍物之一,小恐龙碰上就会死掉;

记分板:记录当前的分数和历史最高分。

让我们来依次定义一下这些游戏元素类。对于云,路面以及仙人掌来说,定义起来很简单,我们只需要加载对应的游戏元素图片:

然后写两个类内部方法update和draw就ok了。两个方法分别用于将场景不断向左移动以实现小恐龙不断向前移动的动画效果和将场景显示在游戏界面的对应位置上。具体而言,代码实现如下:

'''地板'''

class Ground(pygame.sprite.Sprite):

def __init__(self, imagepath, position, **kwargs):

pygame.sprite.Sprite.__init__(self)

# 导入图片

self.image_0 = pygame.image.load(imagepath)

self.rect_0 = self.image_0.get_rect()

self.rect_0.left, self.rect_0.bottom = position

self.image_1 = pygame.image.load(imagepath)

self.rect_1 = self.image_1.get_rect()

self.rect_1.left, self.rect_1.bottom = self.rect_0.right, self.rect_0.bottom

# 定义一些必要的参数

self.speed = -10

'''更新地板'''

def update(self):

self.rect_0.left += self.speed

self.rect_1.left += self.speed

if self.rect_0.right < 0:

self.rect_0.left = self.rect_1.right

if self.rect_1.right < 0:

self.rect_1.left = self.rect_0.right

'''将地板画到屏幕'''

def draw(self, screen):

screen.blit(self.image_0, self.rect_0)

screen.blit(self.image_1, self.rect_1)

'''云'''

class Cloud(pygame.sprite.Sprite):

def __init__(self, imagepath, position, **kwargs):

pygame.sprite.Sprite.__init__(self)

# 导入图片

self.image = pygame.image.load(imagepath)

self.rect = self.image.get_rect()

self.rect.left, self.rect.top = position

# 定义一些必要的参数

self.speed = -1

'''将云画到屏幕上'''

def draw(self, screen):

screen.blit(self.image, self.rect)

'''更新云'''

def update(self):

self.rect = self.rect.move([self.speed, 0])

if self.rect.right < 0:

self.kill()

'''仙人掌'''

class Cactus(pygame.sprite.Sprite):

def __init__(self, imagepaths, position=(600, 147), sizes=[(40, 40), (40, 40)], **kwargs):

pygame.sprite.Sprite.__init__(self)

# 导入图片

self.images = []

image = pygame.image.load(imagepaths[0])

for i in range(3):

self.images.append(pygame.transform.scale(image.subsurface((i*101, 0), (101, 101)), sizes[0]))

image = pygame.image.load(imagepaths[1])

for i in range(3):

self.images.append(pygame.transform.scale(image.subsurface((i*68, 0), (68, 70)), sizes[1]))

self.image = random.choice(self.images)

self.rect = self.image.get_rect()

self.rect.left, self.rect.bottom = position

self.mask = pygame.mask.from_surface(self.image)

# 定义一些必要的变量

self.speed = -10

'''画到屏幕上'''

def draw(self, screen):

screen.blit(self.image, self.rect)

'''更新'''

def update(self):

self.rect = self.rect.move([self.speed, 0])

if self.rect.right < 0:

self.kill()

记分板的定义也类似,只不过它不需要移动,但是需要实时地更新当前 的分数:

'''记分板'''

class Scoreboard(pygame.sprite.Sprite):

def __init__(self, imagepath, position, size=(11, 13), is_highest=False, bg_color=None, **kwargs):

pygame.sprite.Sprite.__init__(self)

# 导入图片

self.images = []

image = pygame.image.load(imagepath)

for i in range(12):

self.images.append(pygame.transform.scale(image.subsurface((i*20, 0), (20, 24)), size))

if is_highest:

self.image = pygame.Surface((size[0]*8, size[1]))

else:

self.image = pygame.Surface((size[0]*5, size[1]))

self.rect = self.image.get_rect()

self.rect.left, self.rect.top = position

# 一些必要的变量

self.is_highest = is_highest

self.bg_color = bg_color

self.score = '00000'

'''设置得分'''

def set(self, score):

self.score = str(score).zfill(5)

'''画到屏幕上'''

def draw(self, screen):

self.image.fill(self.bg_color)

for idx, digital in enumerate(list(self.score)):

digital_image = self.images[int(digital)]

if self.is_highest:

self.image.blit(digital_image, ((idx+3)*digital_image.get_rect().width, 0))

else:

self.image.blit(digital_image, (idx*digital_image.get_rect().width, 0))

if self.is_highest:

self.image.blit(self.images[-2], (0, 0))

self.image.blit(self.images[-1], (digital_image.get_rect().width, 0))

screen.blit(self.image, self.rect)

上面代码用is_highest变量来区分该记分板是否用于记录游戏最高分,还是只是记录当前的分数,做该区分的原因是游戏最高分前面有HI标识,所以占的空间更大:

飞龙的定义就稍微复杂一些了,因为它不仅需要向左移动,还需要做出不停扇动翅膀的效果。具体而言,飞龙有两张图:

你需要做的就是每隔一段时间就切换一次当前的飞龙图片,以实现飞龙扇动翅膀的效果:

'''飞龙'''

class Ptera(pygame.sprite.Sprite):

def __init__(self, imagepath, position, size=(46, 40), **kwargs):

pygame.sprite.Sprite.__init__(self)

# 导入图片

self.images = []

image = pygame.image.load(imagepath)

for i in range(2):

self.images.append(pygame.transform.scale(image.subsurface((i*92, 0), (92, 81)), size))

self.image_idx = 0

self.image = self.images[self.image_idx]

self.rect = self.image.get_rect()

self.rect.left, self.rect.centery = position

self.mask = pygame.mask.from_surface(self.image)

# 定义一些必要的变量

self.speed = -10

self.refresh_rate = 10

self.refresh_counter = 0

'''画到屏幕上'''

def draw(self, screen):

screen.blit(self.image, self.rect)

'''更新'''

def update(self):

if self.refresh_counter % self.refresh_rate == 0:

self.refresh_counter = 0

self.image_idx = (self.image_idx + 1) % len(self.images)

self.loadImage()

self.rect = self.rect.move([self.speed, 0])

if self.rect.right < 0:

self.kill()

self.refresh_counter += 1

'''载入当前状态的图片'''

def loadImage(self):

self.image = self.images[self.image_idx]

rect = self.image.get_rect()

rect.left, rect.top = self.rect.left, self.rect.top

self.rect = rect

self.mask = pygame.mask.from_surface(self.image)

最后,我们需要定义一下小恐龙类,也就是最复杂的一个游戏精灵类。它有低头,跳跃,普通前进三种状态。对于低头来说:

你只需要和飞龙扇动翅膀一样,不断切换两张低头的图片以实现小恐龙跑动的效果就可以了。对于普通状态也是类似的:

对于跳跃状态,我们则可以通过初中学的上抛和自由落体运动公式来建模,从而计算小恐龙在竖直方向上的位置。具体而言,代码实现如下:

'''小恐龙'''

class Dinosaur(pygame.sprite.Sprite):

def __init__(self, imagepaths, position=(40, 147), size=[(44, 47), (59, 47)], **kwargs):

pygame.sprite.Sprite.__init__(self)

# 导入所有图片

self.images = []

image = pygame.image.load(imagepaths[0])

for i in range(5):

self.images.append(pygame.transform.scale(image.subsurface((i*88, 0), (88, 95)), size[0]))

image = pygame.image.load(imagepaths[1])

for i in range(2):

self.images.append(pygame.transform.scale(image.subsurface((i*118, 0), (118, 95)), size[1]))

self.image_idx = 0

self.image = self.images[self.image_idx]

self.rect = self.image.get_rect()

self.rect.left, self.rect.bottom = position

self.mask = pygame.mask.from_surface(self.image)

# 定义一些必要的变量

self.init_position = position

self.refresh_rate = 5

self.refresh_counter = 0

self.speed = 11.5

self.gravity = 0.6

self.is_jumping = False

self.is_ducking = False

self.is_dead = False

self.movement = [0, 0]

'''跳跃'''

def jump(self, sounds):

if self.is_dead or self.is_jumping:

return

sounds['jump'].play()

self.is_jumping = True

self.movement[1] = -1 * self.speed

'''低头'''

def duck(self):

if self.is_jumping or self.is_dead:

return

self.is_ducking = True

'''不低头'''

def unduck(self):

self.is_ducking = False

'''死掉了'''

def die(self, sounds):

if self.is_dead:

return

sounds['die'].play()

self.is_dead = True

'''将恐龙画到屏幕'''

def draw(self, screen):

screen.blit(self.image, self.rect)

'''载入当前状态的图片'''

def loadImage(self):

self.image = self.images[self.image_idx]

rect = self.image.get_rect()

rect.left, rect.top = self.rect.left, self.rect.top

self.rect = rect

self.mask = pygame.mask.from_surface(self.image)

'''更新小恐龙'''

def update(self):

if self.is_dead:

self.image_idx = 4

self.loadImage()

return

if self.is_jumping:

self.movement[1] += self.gravity

self.image_idx = 0

self.loadImage()

self.rect = self.rect.move(self.movement)

if self.rect.bottom >= self.init_position[1]:

self.rect.bottom = self.init_position[1]

self.is_jumping = False

elif self.is_ducking:

if self.refresh_counter % self.refresh_rate == 0:

self.refresh_counter = 0

self.image_idx = 5 if self.image_idx == 6 else 6

self.loadImage()

else:

if self.refresh_counter % self.refresh_rate == 0:

self.refresh_counter = 0

if self.image_idx == 1:

self.image_idx = 2

elif self.image_idx == 2:

self.image_idx = 3

else:

self.image_idx = 1

self.loadImage()

self.refresh_counter += 1

定义完游戏精灵类,我们就可以实例化他们:

# 定义一些游戏中必要的元素和变量

score = 0

score_board = Scoreboard(cfg.IMAGE_PATHS['numbers'], position=(534, 15), bg_color=cfg.BACKGROUND_COLOR)

highest_score = highest_score

highest_score_board = Scoreboard(cfg.IMAGE_PATHS['numbers'], position=(435, 15), bg_color=cfg.BACKGROUND_COLOR, is_highest=True)

dino = Dinosaur(cfg.IMAGE_PATHS['dino'])

ground = Ground(cfg.IMAGE_PATHS['ground'], position=(0, cfg.SCREENSIZE[1]))

cloud_sprites_group = pygame.sprite.Group()

cactus_sprites_group = pygame.sprite.Group()

ptera_sprites_group = pygame.sprite.Group()

add_obstacle_timer = 0

score_timer = 0

然后写游戏主循环啦:

# 游戏主循环

clock = pygame.time.Clock()

while True:

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:

dino.jump(sounds)

elif event.key == pygame.K_DOWN:

dino.duck()

elif event.type == pygame.KEYUP and event.key == pygame.K_DOWN:

dino.unduck()

screen.fill(cfg.BACKGROUND_COLOR)

# --随机添加云

if len(cloud_sprites_group) < 5 and random.randrange(0, 300) == 10:

cloud_sprites_group.add(Cloud(cfg.IMAGE_PATHS['cloud'], position=(cfg.SCREENSIZE[0], random.randrange(30, 75))))

# --随机添加仙人掌/飞龙

add_obstacle_timer += 1

if add_obstacle_timer > random.randrange(50, 150):

add_obstacle_timer = 0

random_value = random.randrange(0, 10)

if random_value >= 5 and random_value <= 7:

cactus_sprites_group.add(Cactus(cfg.IMAGE_PATHS['cacti']))

else:

position_ys = [cfg.SCREENSIZE[1]*0.82, cfg.SCREENSIZE[1]*0.75, cfg.SCREENSIZE[1]*0.60, cfg.SCREENSIZE[1]*0.20]

ptera_sprites_group.add(Ptera(cfg.IMAGE_PATHS['ptera'], position=(600, random.choice(position_ys))))

# --更新游戏元素

dino.update()

ground.update()

cloud_sprites_group.update()

cactus_sprites_group.update()

ptera_sprites_group.update()

score_timer += 1

if score_timer > (cfg.FPS//12):

score_timer = 0

score += 1

score = min(score, 99999)

if score > highest_score:

highest_score = score

if score % 100 == 0:

sounds['point'].play()

if score % 1000 == 0:

ground.speed -= 1

for item in cloud_sprites_group:

item.speed -= 1

for item in cactus_sprites_group:

item.speed -= 1

for item in ptera_sprites_group:

item.speed -= 1

# --碰撞检测

for item in cactus_sprites_group:

if pygame.sprite.collide_mask(dino, item):

dino.die(sounds)

for item in ptera_sprites_group:

if pygame.sprite.collide_mask(dino, item):

dino.die(sounds)

# --将游戏元素画到屏幕上

dino.draw(screen)

ground.draw(screen)

cloud_sprites_group.draw(screen)

cactus_sprites_group.draw(screen)

ptera_sprites_group.draw(screen)

score_board.set(score)

highest_score_board.set(highest_score)

score_board.draw(screen)

highest_score_board.draw(screen)

# --更新屏幕

pygame.display.update()

clock.tick(cfg.FPS)

# --游戏是否结束

if dino.is_dead:

break

游戏主循环的逻辑很简单,即每帧游戏画面,我们都需要检测一下玩家的操作,如果玩家按下了空格键或者↑键,则小恐龙跳跃,如果玩家按下了↓键,则小恐龙低头,否则小恐龙正常向前冲。

然后在游戏中,我们随机产生云,飞龙和仙人掌这些游戏场景和障碍物,并且和路面一起以相同的速度向左移动,从而实现小恐龙向右移动的视觉效果。在移动的过程中,我们需要对小恐龙和仙人掌,小恐龙和飞龙进行碰撞检测,当小恐龙碰到这些障碍物时,小恐龙就死掉了,本局游戏也随之结束。

需要注意的是我们应该使用collide_mask函数来进行更为精确的碰撞检测,而不是之前的collide_rect函数:

即当两个目标的最小外接矩形有重叠时,collide_rect就会判定两个目标有碰撞,这显然是不合理的,会给玩家带来较差的游戏体验。

另外,当分数每提高一千分,我们就和原版的游戏一样增加一点场景和障碍物向左移动的速度(也就是增加小恐龙向右移动的速度)。

最后,把当前所有的游戏元素绑定到屏幕上并更新当前的屏幕就ok了。

java小恐龙游戏_用Python实现谷歌的小恐龙游戏相关推荐

  1. python实现图片找不同游戏_用Python实现谷歌的小恐龙游戏

    (给Python开发者加星标,提升Python技能) 来源: Charles的皮卡丘-白露未晞me理 谷歌流量器中有个很有名的彩蛋:当你网络出现问题时,就会出现一个"小恐龙游戏". ...

  2. 小恐龙游戏python_用Python实现谷歌的小恐龙游戏:p

    Python版本:3.6.4 相关模块: pygame模块: 以及一些python自带的模块. 环 境 搭 建 安装Python并添加到环境变量,pip安装需要的相关模块即可. 先 睹 为 快 在终端 ...

  3. 怎么用python编简单游戏_用Python实现一个简单的算术游戏详解

    用Python实现一个简单的算术游戏 #!/usr/bin/env python from operator import add, sub from random import randint, c ...

  4. python pygame模块怎么写游戏_使用 Python 和 Pygame 模块构建一个游戏框架

    这系列的第一篇通过创建一个简单的骰子游戏来探究 Python.现在是来从零制作你自己的游戏的时间. 在我的这系列的第一篇文章 中, 我已经讲解如何使用 Python 创建一个简单的.基于文本的骰子游戏 ...

  5. python 小括号 运算_浅析python 中大括号中括号小括号的区分

    python语言最常见的括号有三种,分别是:小括号( ).中括号[ ]和大括号也叫做花括号{ }.其作用也各不相同,分别用来代表不同的python基本内置数据类型. 1.python中的小括号( ): ...

  6. python画恐龙_用Python实现谷歌的小恐龙游戏

    '''云'''classCloud( pygame. sprite. Sprite):def__init__( self, imagepath, position, **kwargs):pygame. ...

  7. python连连看小游戏_利用Python制作一个连连看小游戏,边学边玩!

    导语 今天我们将制作一个连连看小游戏,让我们愉快地开始吧~ 开发工具 Python版本:3.6.4 相关模块: pygame模块: 以及一些Python自带的模块 环境搭建 安装Python并添加到环 ...

  8. python可视化窗口制作一个摇骰子游戏_使用python制作一个抽奖小游戏——骰子游戏...

    1.模拟真实环境掷骰子 从Python标准库中调用模块:random--random中包含以各种方式生成随机数的函数 从random中引用randint这一函数--骰子都是有固定面数 from ran ...

  9. pygame做的著名游戏_用python写游戏之2D跑酷游戏(一)

    2D的跑酷游戏有很多,著名的例如Chrome的彩蛋小游戏,手机上的天天酷跑等. 打开Chrome浏览器输入 chrome://dino/,按空格激活彩蛋 这篇文章来分析一下这类横版跑酷游戏的主角奔跑, ...

最新文章

  1. vs2015下载 简体中文版/企业版 附邀请码
  2. mysql中groupby会用到索引吗_mysql order by 与索引的使用
  3. c语言万年历闹钟程序,c语言编写的万年历 有平年闰年 有闹钟功能.docx
  4. Linux应用:FTP
  5. 接口测试基础——第5篇xlrd模块
  6. 7-27 通讯录的录入与显示 (10 分)
  7. Omnibus test
  8. PHP laravel框架Redis门面的误用
  9. 从零基础入门Tensorflow2.0 ----二、4.2 wide deep 模型(子类API)
  10. 消息队列kafka知识总结
  11. MapReduce计算框架知识总结(一)
  12. MFC中.和-的区别
  13. 关于测量物体空间位置的装置
  14. Excel数据导入___你hold住么(二)
  15. [附源码]Nodejs计算机毕业设计基于Yigo平台库房管理系统Express(程序+LW)
  16. matlab小船渡河物理模型,高中物理 | 小船渡河模型和斜拉船模型
  17. Rhombus 使用 Wolfspeed SiC 加快电动汽车充电速度
  18. Java多线程(上篇)
  19. 拼搏别样的未来,中国社科院与美国杜兰大学金融管理硕士项目助力你的人生旅程
  20. 【EasyClick iOS免越狱常见问题】iPhone重启后无法启动代理程序

热门文章

  1. 4h上手C++版Opencv
  2. 告诉你游戏服务器到底是什么
  3. mini2440 sd卡加载过程详解
  4. shell awk监控磁盘使用率
  5. 2020大数据领域十大必读书籍
  6. Android进程保活黑科技实现原理解密及方法,最新整理
  7. Unity获取摄像头权限
  8. 『项目管理』用ALPEN法则来安排每日工作进度|把时间留给最重要的事
  9. 多对一(Many2One)
  10. Matplotlib数据可视化高级