python画恐龙_教你用Python实现谷歌的小恐龙游戏

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

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

d03562c7b6eb9605bacfd9cca1ead009.png

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

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

开发工具:

Python版本:3.6.4

相关模块:

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

环境搭建

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

先睹为快

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

python Game7.py

1b62f6b75faa1d44d68f0c3a58b60832.png

d163c4e96ad49cb42b1e49c139be5c46.png

代码介绍

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

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

# 游戏初始化

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)

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

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

路面:游戏的背景;

云:游戏的背景;

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

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

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

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

c8a84466a6bc15131181572a17d00027.png

6a7d3134859e3b226a2171dd9250ae63.png

该图片来源:网页游戏http://www.hp91.cn/网页游戏

然后写两个类内部方法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标识,所以占的空间更大:

564a4c71fb04fd81762890f9c7f1043e.png

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

698b91156eb411189410cd38e66efd6e.png

该图片来源:网页游戏http://www.hp91.cn/网页游戏

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

'''飞龙'''

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)

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

edcbc2601d18d30b158655ae231593de.png

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

5be631e1b6d946b4384a0ed235cd4d35.png

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

'''小恐龙'''

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函数:

a4a3a1c92b0918b4c5fedf4b06c9dba8.png

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

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

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

  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
【资源说明】 Python开发基于机器学习实现自动玩Google小恐龙游戏源码+项目说明+注释拉满.zip 如何用人工智能自动玩游戏 ## 一、前言 让AI玩游戏的思想早在上世纪就已经有了,那个时候更偏向棋类游戏。像是五子棋、象棋等。在上世纪“深蓝”就击败了国际象棋冠军,而到2016年“Alpha Go”击败了人类围棋冠军。 到现在,AI涉略的不仅仅是棋类游戏。像是超级马里奥、王者荣耀这种游戏,AI也能有比较好的表现。今天我们就来用一个实际的例子讨论AI自动玩游戏这一话题,本文会用非常简单的机器学习算法让AI自动玩Google小恐龙游戏。 ## 二、Google小恐龙与监督学习 ### 2.1、Google小恐龙 如果你使用的是Chrome浏览器,那么相信你应该见过下面这个恐龙: ![在这里插入图片描述](https://img-blog.csdnimg.cn/f6cd242ae82248759165688539d6c521.png#pic_center) 当我们用Chrome断网访问网页时,就会显示这个恐龙,或者直接在地址栏输入:[chrome://dino](chrome://dino)直接访问该游戏游戏的玩法非常简单,只需要按空格键即可。比如下面左图,快碰到障碍物,这时需要按空格,而下面右图没有障碍(或离障碍比较远),则不需要按按键。 ![在这里插入图片描述](https://img-blog.csdnimg.cn/2ba95fbf96e84d0aa3bc49fe1fb9fc9b.png#pic_center) 当然还有出现鸟的情况,我们也可以归为跳的情况。大家可以玩一下。 ### 2.2、监督学习 玩游戏很多时候会使用一个叫强化学习的方式来实现,而本文使用比较简单的监督学习来实现。 【备注】 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用! 2、本项目适合计算机相关专业(如计科、人工智能、通信工程、自动化、电子信息等)的在校学生、老师或者企业员工下载使用,也适合小白学习进阶,当然也可作为毕设项目、课程设计、作业、项目初期立项演示等。 3、如果基础还行,也可在此代码基础上进行修改,以实现其他功能,也可直接用于毕设、课设、作业等。 欢迎下载,沟通交流,互相学习,共同进步!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值