python做游戏用什么软件_用Python自制谷歌小游戏

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

(如果想要直接进行游戏,可以在地址栏输入: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了。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/277541.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

使用maven构建项目候,jar包错误的解决办法

1、删除架包&#xff0c;重新下载&#xff0c;右键项目点击"run as"中的“maven clean”,然后再maven中找到Update Project 2、可以在代码中&#xff0c;把鼠标放到报错的架包上 点击划红线部分&#xff0c;进行安装 转载于:https://www.cnblogs.com/qingqian/p/1099…

MySQL——通过EXPLAIN分析SQL的执行计划

在MySQL中&#xff0c;我们可以通过EXPLAIN命令获取MySQL如何执行SELECT语句的信息&#xff0c;包括在SELECT语句执行过程中表如何连接和连接的顺序。下面分别对EXPLAIN命令结果的每一列进行说明&#xff1a;select_type:表示SELECT的类型&#xff0c;常见的取值有&#xff1a;…

python将argv作为参数_在jupyter / ipython notebook中将命令行参数传递给argv

经过大量的环顾后,我发现了非常繁琐的自定义库,但是用几行代码解决了它,我认为这些代码很漂亮.我使用nbconvert最终得到一个html报告作为输出,包含笔记本中的所有图形和降价,但是通过最小的python包装器接受命令行参数&#xff1a;python文件test_args.py(正常执行命令行参数)&…

模拟输入(ADC-A0)

ESP8266具有内置的10位ADC&#xff0c;只有一个ADC通道(A0引脚)&#xff0c;即只有一个ADC输入引脚可读取来自外部器件的模拟电压 ESP8266上的ADC通道和芯片供电电压复用&#xff0c;也就是说我们可以将其设置为测量系统电压或者外部电压 测量外部电压&#xff1a; analogRead(…

SQL Server 连接超时案例一则

原文:SQL Server 连接超时案例一则上周六&#xff0c;一工厂系统管理员反馈一数据库连接不上&#xff0c;SSMS连接数据库报“连接超时时间已到。在尝试使用预登录握手确认时超过了此超时时间.......”, 如下截图所示&#xff1a; 另外远程连接也连接不上&#xff0c;系统管理员…

mysql 删除5天前 备份_mysql自动备份删除5天前的备份

1、查看磁盘空间情况&#xff1a;df -h2、创建备份目录&#xff1a;上面我们使用命令看出/home下空间比较充足&#xff0c;所以可以考虑在/home保存备份文件&#xff1b;cd /homemkdir backupcd backup3、创建备份Shell脚本:注意把以下命令中的DatabaseName换为实际的数据库名称…

个人作业-Alpha项目测试

这个作业属于哪个课程https://edu.cnblogs.com/campus/xnsy/SoftwareEngineeringClass2作业地址https://edu.cnblogs.com/campus/xnsy/SoftwareEngineeringClass2/homework/3340团队名称脑阔疼https://www.cnblogs.com/chaserFF/p/10994338.html这个作业的目标完成班级项目互评…

深入理解brew link命令

来源&#xff1a;https://newsn.net/say/brew-link-php71.html brew是mac机上面程序猿非常常用的软件包安装方式&#xff0c;其中有两组命令是需要大家知晓的。分别是&#xff1a;第一组&#xff1a;brew install和brew uninstall。第二组&#xff0c;brew link和brew unlink。…

scss2css vscode设置_VSCode下让CSS文件完美支持SCSS或SASS语法方法

VSCode下让CSS文件完美支持SCSS或SASS语法方法习惯Webpack PostCSS后, 通常PostCSS都是直接对CSS文件进行处理, 但是大部分习惯SCSS/SASS/LESS的朋友也许不适应了. 我专门研究了一下, 在Visual Studio Code编辑器下如果配置相关代码和设置达到CSS文件完美编写SCSS的办法, 其他…

第5章 初识JQuery

JQuery是对JavaScript的封装&#xff0c;简化了JS代码&#xff0c;是主流框架的基础(VUE,EasyUI,Bootstrap) 它是2006年推出的JQuery的优势&#xff1a; 体积小&#xff0c;压缩后只有100KB左右 强大的选择器 出色的DOM封装 可靠的事件处理机制 出色的浏览器兼容性 使用隐式迭代…

Jenkins的Pipeline脚本在美团餐饮SaaS中的实践

2019独角兽企业重金招聘Python工程师标准>>> 一、背景 在日常开发中&#xff0c;我们经常会有发布需求&#xff0c;而且还会遇到各种环境&#xff0c;比如&#xff1a;线上环境&#xff08;Online&#xff09;&#xff0c;模拟环境&#xff08;Staging&#xff09;&…

6.12交流

czy bzoj5424烧桥计划 f[i][j]暴力&#xff0c;可以分两段转移&#xff0c;更近的一段单调队列 发现&#xff0c;最多分成sqrt(n)段。 因为如果只有一段&#xff0c;ansn*2000 而如果多段&#xff0c;至少是∑i*1000&#xff0c;那么&#xff0c;i的上界是sqrt(n)级别的。 所以…

java椭圆_如何用java画椭圆

该楼层疑似违规已被系统折叠 隐藏此楼查看此楼利用java画出椭圆。也就是鼠标一边移动一边显示出椭圆&#xff0c;如何做到请大神指教这是我写的(没有达到我自己的要求)&#xff1a;import java.awt.*;import java.awt.Graphics;import java.awt.event.*;import javax.swing.*;i…

【springboot+easypoi】一行代码搞定excel导入导出

原文&#xff1a;https://www.jianshu.com/p/5d67fb720ece 开发中经常会遇到excel的处理&#xff0c;导入导出解析等等&#xff0c;java中比较流行的用poi&#xff0c;但是每次都要写大段工具类来搞定这事儿&#xff0c;此处推荐一个别人造好的轮子【easypoi】&#xff0c;下面…

用java编写一个计算器_用java程序编写一个计算器

展开全部给你一个参考&#xff0c;希望不62616964757a686964616fe58685e5aeb931333330343261要被百度吞了当晚餐import java.awt.BorderLayout;import java.awt.GridLayout;import java.awt.event.MouseEvent;import java.awt.event.MouseListener;import java.text.DecimalFor…

TypeScript基础入门 - 接口 - 可索引的类型

转载地址 TypeScript基础入门 - 接口 - 可索引的类型 项目实践仓库 https://github.com/durban89/typescript_demo.git tag: 1.0.11 为了保证后面的学习演示需要安装下ts-node&#xff0c;这样后面的每个操作都能直接运行看到输出的结果。 npm install -D ts-node 后面自己在练…

jquery中的ajax方法(备忘)

参考&#xff1a;https://www.cnblogs.com/tylerdonet/p/3520862.html w3school:http://www.w3school.com.cn/jquery/ajax_ajax.asp 1.url: 要求为String类型的参数&#xff0c;&#xff08;默认为当前页地址&#xff09;发送请求的地址。 2.type: 要求为String类型的参数&…

java高级类_Java高级类特性(一)

权限类内同包不同包子类不同包非子类private√default√√protected√√√public√√√√四、super关键字的使用package com.test.java;/** super可以用来修饰属性、方法、构造器* 1)当子类与父类中有同名的属性时&#xff0c;可以通过"super.属性"显式的调用父类中声…

Android.对话框(AlertDialog/Toast/Snackbar)

1、资料&#xff1a; 1.1、Android提醒微技巧&#xff0c;你真的了解Dialog、Toast和Snackbar吗&#xff1f; - CSDN博客.html&#xff08;https://blog.csdn.net/guolin_blog/article/details/51336415&#xff09; 1.2、Android界面设计之对话框——定制Toast、AlertDialog -…

第4次作业

转载于:https://www.cnblogs.com/wzh2920330283/p/11027254.html