少儿编程之使用PyGame编写游戏(13):太空大撞击 添加几条命

玩家爆炸

我们将为玩家的死亡使用不同的爆炸动画,同样来自同一个 Kenny Game Art包,称为“Sonic Explosion”。
我们只需要像处理其他爆炸一样加载这些帧。 我们将添加另一个名为“player”的爆炸类型并在同一个循环中加载它,因为它与我们正在加载的另一个爆炸具有相同的帧数。 现在我们的加载代码将如下所示:

  1. explosion_anim = {}
  2. explosion_anim['lg'] = []
  3. explosion_anim['sm'] = []
  4. explosion_anim['player'] = []
  5. for i in range(9):
  6. filename = 'regularExplosion0{}.png'.format(i)
  7. img = pygame.image.load(path.join(img_dir, filename)).convert()
  8. img.set_colorkey(BLACK)
  9. img_lg = pygame.transform.scale(img, (75, 75))
  10. explosion_anim['lg'].append(img_lg)
  11. img_sm = pygame.transform.scale(img, (32, 32))
  12. explosion_anim['sm'].append(img_sm)
  13. filename = 'sonicExplosion0{}.png'.format(i)
  14. img = pygame.image.load(path.join(img_dir, filename)).convert()
  15. img.set_colorkey(BLACK)
  16. explosion_anim['player'].append(img)

我们不需要更改 Explosion 精灵 类中的任何内容,因此我们只需要在玩家的生命值耗尽时创建一个玩家爆炸对象。 我们可以在检查玩家与Mob碰撞的游戏循环中添加它:

  1. # check to see if a mob hit the player
  2. hits = pygame.sprite.spritecollide(player, mobs, True, pygame.sprite.collide_circle)
  3. for hit in hits:
  4. player.shield -= hit.radius * 2
  5. expl = Explosion(hit.rect.center, 'sm')
  6. all_sprites.add(expl)
  7. newmob()
  8. if player.shield <= 0:
  9. death_explosion = Explosion(player.rect.center, 'player')
  10. all_sprites.add(death_explosion)
  11. running = False

但是如果你运行程序,你会发现我们现在遇到了一个问题:当玩家死亡时,因为我们将 running 设置成了 False,所以游戏在我们有机会看到漂亮的爆炸之前就结束了!

为了解决这个问题,我们需要在爆炸结束之后结束游戏。 所以我们将删除玩家角色,但直到爆炸消失才将running设置成False:

  1. if player.shield <= 0:
  2. death_explosion = Explosion(player.rect.center, 'player')
  3. all_sprites.add(death_explosion)
  4. player.kill()
  5. # if the player died and the explosion has finished playing
  6. if not player.alive() and not death_explosion.alive():
  7. running = False

alive() 函数只返回一个特定的精灵是否还活着。 因为我们在爆炸结束时 使用kill() 删除Explosion对象,所以我们现在可以在爆炸结束时再结束游戏。

几条命

现在我们要赋予玩家多条生命(lives)。 我们可以用一个变量来跟踪它,同时我们也希望能够在屏幕上显示它。 与其只显示一个数字,不如使用玩家飞船的较小图像来显示还剩多少生命会更好看。 首先,我们将创建较小的图像:

  1. player_img = pygame.image.load(path.join(img_dir, "playerShip1_orange.png")).convert()
  2. player_mini_img = pygame.transform.scale(player_img, (25, 19))
  3. player_mini_img.set_colorkey(BLACK)

现在我们将向 Player 类 __init__() 添加一些新参数:一个生命计数器,一个用于隐藏/显示玩家的标志(可以是 True 或 False 的变量),以及一个用于控制玩家隐藏多长时间的计时器:

  1. self.lives = 3
  2. self.hidden = False
  3. self.hide_timer = pygame.time.get_ticks()

现在,当玩家死亡时,我们将隐藏玩家并从生命中减去 1,而不是使用 kill()。 我们还为玩家的下一条命重置了生命值:

  1. if player.shield <= 0:
  2. death_explosion = Explosion(player.rect.center, 'player')
  3. all_sprites.add(death_explosion)
  4. player.hide()
  5. player.lives -= 1
  6. player.shield = 100
  7. # if the player died and the explosion has finished playing
  8. if player.lives == 0 and not death_explosion.alive():
  9. running = False

接下来,我们需要定义隐藏的工作原理。 回到 Player 类中,我们将添加一个 hide 方法,它将隐藏标志设置为 True 并启动计时器。 我们还需要确保玩家在隐藏时不会被Mob击中。 实现方式没什么选择,我们使用一种不需要从精灵组中添加/删除等的简单方法是暂时将玩家角色移出屏幕底部:

  1. def hide(self):
  2. # hide the player temporarily
  3. self.hidden = True
  4. self.hide_timer = pygame.time.get_ticks()
  5. self.rect.center = (WIDTH / 2, HEIGHT + 200)

在玩家的 update() 方法中,如果计时器经过足够的时间,我们需要取消玩家隐藏(我们现在使用 1 秒):

  1. def update(self):
  2. # unhide if hidden
  3. if self.hidden and pygame.time.get_ticks() - self.hide_timer > 1000:
  4. self.hidden = False
  5. self.rect.centerx = WIDTH / 2
  6. self.rect.bottom = HEIGHT - 10

生命计数器显示

为了显示生命值,我们将创建一个类似于 draw_shield_bar() 的函数,它将让我们将生命计数器放置在给定位置:

  1. def draw_lives(surf, x, y, lives, img):
  2. for i in range(lives):
  3. img_rect = img.get_rect()
  4. img_rect.x = x + 30 * i
  5. img_rect.y = y
  6. surf.blit(img, img_rect)

我们只是根据生命的数量来绘制图像,将每个图像间隔 30 像素(player_mini_img 是 25 像素宽,因此它们之间会留出很小的空间)。
然后,在我们的游戏循环的绘图部分添加对这个函数的调用:

  1. draw_lives(screen, WIDTH - 100, 5, player.lives,
  2. player_mini_img)

最终效果如下图所示:

完整代码请点击此处查看。
封面图片来自UnSplash

微信扫一扫,分享此文章

少儿编程教学平台

联系我们

微信

aguibo002

邮箱

haoxuehaojiao在163.com

Loading
我们已经收到您的信息,将尽快联系您!