玩家爆炸
我们将为玩家的死亡使用不同的爆炸动画,同样来自同一个 Kenny Game Art包,称为“Sonic Explosion”。
我们只需要像处理其他爆炸一样加载这些帧。 我们将添加另一个名为“player”的爆炸类型并在同一个循环中加载它,因为它与我们正在加载的另一个爆炸具有相同的帧数。 现在我们的加载代码将如下所示:
explosion_anim = {}
explosion_anim['lg'] = []
explosion_anim['sm'] = []
explosion_anim['player'] = []
for i in range(9):
filename = 'regularExplosion0{}.png'.format(i)
img = pygame.image.load(path.join(img_dir, filename)).convert()
img.set_colorkey(BLACK)
img_lg = pygame.transform.scale(img, (75, 75))
explosion_anim['lg'].append(img_lg)
img_sm = pygame.transform.scale(img, (32, 32))
explosion_anim['sm'].append(img_sm)
filename = 'sonicExplosion0{}.png'.format(i)
img = pygame.image.load(path.join(img_dir, filename)).convert()
img.set_colorkey(BLACK)
explosion_anim['player'].append(img)
我们不需要更改 Explosion 精灵 类中的任何内容,因此我们只需要在玩家的生命值耗尽时创建一个玩家爆炸对象。 我们可以在检查玩家与Mob碰撞的游戏循环中添加它:
# check to see if a mob hit the player
hits = pygame.sprite.spritecollide(player, mobs, True, pygame.sprite.collide_circle)
for hit in hits:
player.shield -= hit.radius * 2
expl = Explosion(hit.rect.center, 'sm')
all_sprites.add(expl)
newmob()
if player.shield <= 0:
death_explosion = Explosion(player.rect.center, 'player')
all_sprites.add(death_explosion)
running = False
但是如果你运行程序,你会发现我们现在遇到了一个问题:当玩家死亡时,因为我们将 running 设置成了 False,所以游戏在我们有机会看到漂亮的爆炸之前就结束了!
为了解决这个问题,我们需要在爆炸结束之后结束游戏。 所以我们将删除玩家角色,但直到爆炸消失才将running设置成False:
if player.shield <= 0:
death_explosion = Explosion(player.rect.center, 'player')
all_sprites.add(death_explosion)
player.kill()
# if the player died and the explosion has finished playing
if not player.alive() and not death_explosion.alive():
running = False
alive() 函数只返回一个特定的精灵是否还活着。 因为我们在爆炸结束时 使用kill() 删除Explosion对象,所以我们现在可以在爆炸结束时再结束游戏。
几条命
现在我们要赋予玩家多条生命(lives)。 我们可以用一个变量来跟踪它,同时我们也希望能够在屏幕上显示它。 与其只显示一个数字,不如使用玩家飞船的较小图像来显示还剩多少生命会更好看。 首先,我们将创建较小的图像:
player_img = pygame.image.load(path.join(img_dir, "playerShip1_orange.png")).convert()
player_mini_img = pygame.transform.scale(player_img, (25, 19))
player_mini_img.set_colorkey(BLACK)
现在我们将向 Player 类 __init__()
添加一些新参数:一个生命计数器,一个用于隐藏/显示玩家的标志(可以是 True 或 False 的变量),以及一个用于控制玩家隐藏多长时间的计时器:
self.lives = 3
self.hidden = False
self.hide_timer = pygame.time.get_ticks()
现在,当玩家死亡时,我们将隐藏玩家并从生命中减去 1,而不是使用 kill()。 我们还为玩家的下一条命重置了生命值:
if player.shield <= 0:
death_explosion = Explosion(player.rect.center, 'player')
all_sprites.add(death_explosion)
player.hide()
player.lives -= 1
player.shield = 100
# if the player died and the explosion has finished playing
if player.lives == 0 and not death_explosion.alive():
running = False
接下来,我们需要定义隐藏的工作原理。 回到 Player 类中,我们将添加一个 hide 方法,它将隐藏标志设置为 True 并启动计时器。 我们还需要确保玩家在隐藏时不会被Mob击中。 实现方式没什么选择,我们使用一种不需要从精灵组中添加/删除等的简单方法是暂时将玩家角色移出屏幕底部:
def hide(self):
# hide the player temporarily
self.hidden = True
self.hide_timer = pygame.time.get_ticks()
self.rect.center = (WIDTH / 2, HEIGHT + 200)
在玩家的 update() 方法中,如果计时器经过足够的时间,我们需要取消玩家隐藏(我们现在使用 1 秒):
def update(self):
# unhide if hidden
if self.hidden and pygame.time.get_ticks() - self.hide_timer > 1000:
self.hidden = False
self.rect.centerx = WIDTH / 2
self.rect.bottom = HEIGHT - 10
生命计数器显示
为了显示生命值,我们将创建一个类似于 draw_shield_bar() 的函数,它将让我们将生命计数器放置在给定位置:
def draw_lives(surf, x, y, lives, img):
for i in range(lives):
img_rect = img.get_rect()
img_rect.x = x + 30 * i
img_rect.y = y
surf.blit(img, img_rect)
我们只是根据生命的数量来绘制图像,将每个图像间隔 30 像素(player_mini_img 是 25 像素宽,因此它们之间会留出很小的空间)。
然后,在我们的游戏循环的绘图部分添加对这个函数的调用:
draw_lives(screen, WIDTH - 100, 5, player.lives,
player_mini_img)