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

(给Python开发者加星标,提升Python技能)

来源: Charles的皮卡丘-白露未晞me理

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

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

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

今天我们就来给大家演示下,用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)

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

  • 小恐龙:由玩家控制以躲避路上的障碍物;
  • 路面:游戏的背景;
  • 云:游戏的背景;
  • 飞龙:路上的障碍物之一,小恐龙碰上就会死掉;
  • 仙人掌:路上的障碍物之一,小恐龙碰上就会死掉;
  • 记分板:记录当前的分数和历史最高分。

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

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

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

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

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

'''&#x5730;&#x677F;'''class Ground(pygame.sprite.Sprite):  def __init__(self, imagepath, position, **kwargs):    pygame.sprite.Sprite.__init__(self)    # &#x5BFC;&#x5165;&#x56FE;&#x7247;    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    # &#x5B9A;&#x4E49;&#x4E00;&#x4E9B;&#x5FC5;&#x8981;&#x7684;&#x53C2;&#x6570;    self.speed = -10  '''&#x66F4;&#x65B0;&#x5730;&#x677F;'''  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  '''&#x5C06;&#x5730;&#x677F;&#x753B;&#x5230;&#x5C4F;&#x5E55;'''  def draw(self, screen):    screen.blit(self.image_0, self.rect_0)    screen.blit(self.image_1, self.rect_1)'''&#x4E91;'''class Cloud(pygame.sprite.Sprite):  def __init__(self, imagepath, position, **kwargs):    pygame.sprite.Sprite.__init__(self)    # &#x5BFC;&#x5165;&#x56FE;&#x7247;    self.image = pygame.image.load(imagepath)    self.rect = self.image.get_rect()    self.rect.left, self.rect.top = position    # &#x5B9A;&#x4E49;&#x4E00;&#x4E9B;&#x5FC5;&#x8981;&#x7684;&#x53C2;&#x6570;    self.speed = -1  '''&#x5C06;&#x4E91;&#x753B;&#x5230;&#x5C4F;&#x5E55;&#x4E0A;'''  def draw(self, screen):    screen.blit(self.image, self.rect)  '''&#x66F4;&#x65B0;&#x4E91;'''  def update(self):    self.rect = self.rect.move([self.speed, 0])    if self.rect.right < 0:      self.kill()'''&#x4ED9;&#x4EBA;&#x638C;'''class Cactus(pygame.sprite.Sprite):  def __init__(self, imagepaths, position=(600, 147), sizes=[(40, 40), (40, 40)], **kwargs):    pygame.sprite.Sprite.__init__(self)    # &#x5BFC;&#x5165;&#x56FE;&#x7247;    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)    # &#x5B9A;&#x4E49;&#x4E00;&#x4E9B;&#x5FC5;&#x8981;&#x7684;&#x53D8;&#x91CF;    self.speed = -10  '''&#x753B;&#x5230;&#x5C4F;&#x5E55;&#x4E0A;'''  def draw(self, screen):    screen.blit(self.image, self.rect)  '''&#x66F4;&#x65B0;'''  def update(self):    self.rect = self.rect.move([self.speed, 0])    if self.rect.right < 0:      self.kill()

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

'''&#x8BB0;&#x5206;&#x677F;'''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)    # &#x5BFC;&#x5165;&#x56FE;&#x7247;    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    # &#x4E00;&#x4E9B;&#x5FC5;&#x8981;&#x7684;&#x53D8;&#x91CF;    self.is_highest = is_highest    self.bg_color = bg_color    self.score = '00000'  '''&#x8BBE;&#x7F6E;&#x5F97;&#x5206;'''  def set(self, score):    self.score = str(score).zfill(5)  '''&#x753B;&#x5230;&#x5C4F;&#x5E55;&#x4E0A;'''  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标识,所以占的空间更大:

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

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

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

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

'''&#x98DE;&#x9F99;'''class Ptera(pygame.sprite.Sprite):  def __init__(self, imagepath, position, size=(46, 40), **kwargs):    pygame.sprite.Sprite.__init__(self)    # &#x5BFC;&#x5165;&#x56FE;&#x7247;    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)    # &#x5B9A;&#x4E49;&#x4E00;&#x4E9B;&#x5FC5;&#x8981;&#x7684;&#x53D8;&#x91CF;    self.speed = -10    self.refresh_rate = 10    self.refresh_counter = 0  '''&#x753B;&#x5230;&#x5C4F;&#x5E55;&#x4E0A;'''  def draw(self, screen):    screen.blit(self.image, self.rect)  '''&#x66F4;&#x65B0;'''  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  '''&#x8F7D;&#x5165;&#x5F53;&#x524D;&#x72B6;&#x6001;&#x7684;&#x56FE;&#x7247;'''  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)

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

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

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

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

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

'''&#x5C0F;&#x6050;&#x9F99;'''class Dinosaur(pygame.sprite.Sprite):  def __init__(self, imagepaths, position=(40, 147), size=[(44, 47), (59, 47)], **kwargs):    pygame.sprite.Sprite.__init__(self)    # &#x5BFC;&#x5165;&#x6240;&#x6709;&#x56FE;&#x7247;    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)    # &#x5B9A;&#x4E49;&#x4E00;&#x4E9B;&#x5FC5;&#x8981;&#x7684;&#x53D8;&#x91CF;    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]  '''&#x8DF3;&#x8DC3;'''  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  '''&#x4F4E;&#x5934;'''  def duck(self):    if self.is_jumping or self.is_dead:      return    self.is_ducking = True  '''&#x4E0D;&#x4F4E;&#x5934;'''  def unduck(self):    self.is_ducking = False  '''&#x6B7B;&#x6389;&#x4E86;'''  def die(self, sounds):    if self.is_dead:      return    sounds['die'].play()    self.is_dead = True  '''&#x5C06;&#x6050;&#x9F99;&#x753B;&#x5230;&#x5C4F;&#x5E55;'''  def draw(self, screen):    screen.blit(self.image, self.rect)  '''&#x8F7D;&#x5165;&#x5F53;&#x524D;&#x72B6;&#x6001;&#x7684;&#x56FE;&#x7247;'''  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)  '''&#x66F4;&#x65B0;&#x5C0F;&#x6050;&#x9F99;'''  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

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

&#x5B9A;&#x4E49;&#x4E00;&#x4E9B;&#x6E38;&#x620F;&#x4E2D;&#x5FC5;&#x8981;&#x7684;&#x5143;&#x7D20;&#x548C;&#x53D8;&#x91CF;score = 0score_board = Scoreboard(cfg.IMAGE_PATHS['numbers'], position=(534, 15), bg_color=cfg.BACKGROUND_COLOR)highest_score = highest_scorehighest_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 = 0score_timer = 0

然后写游戏主循环啦:

&#x6E38;&#x620F;&#x4E3B;&#x5FAA;&#x73AF;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)  # --&#x968F;&#x673A;&#x6DFB;&#x52A0;&#x4E91;  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))))  # --&#x968F;&#x673A;&#x6DFB;&#x52A0;&#x4ED9;&#x4EBA;&#x638C;/&#x98DE;&#x9F99;  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> (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  # --&#x78B0;&#x649E;&#x68C0;&#x6D4B;  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)  # --&#x5C06;&#x6E38;&#x620F;&#x5143;&#x7D20;&#x753B;&#x5230;&#x5C4F;&#x5E55;&#x4E0A;  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)  # --&#x66F4;&#x65B0;&#x5C4F;&#x5E55;  pygame.display.update()  clock.tick(cfg.FPS)  # --&#x6E38;&#x620F;&#x662F;&#x5426;&#x7ED3;&#x675F;  if dino.is_dead:    break</=>

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

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

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

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

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

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

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

大概就是这样,大功告成~完整源代码详见相关文件呗~

GitHub地址:https://github.com/CharlesPikachu/Games/tree/master/Game7

  • EOF –

推荐阅读 点击标题可跳转

1、Python 游戏编程之实现飞机大战(含源代码)

2、用 Python 写出 Gameboy 模拟器,还能训练 AI 模型:丹麦小哥的大学项目火了

3、Keras 之父:棋下得好、游戏玩得好未必就是真 AI

觉得本文对你有帮助?请分享给更多人

推荐关注「Python开发者」,提升Python技能

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

点赞和在看就是最大的支持❤️

Original: https://blog.csdn.net/weixin_33477290/article/details/112383140
Author: 风格里哦
Title: python实现图片找不同游戏_用Python实现谷歌的小恐龙游戏

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/782318/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球