球碰到球拍时会发出 hit
声音,下面再增加另外一些声音。我们将为下面这些情况添加声音:
球碰到两边的墙时;
球碰到顶边而且玩家得分时;
玩家漏球,球碰到底边时;
新的一条命开始时;
游戏结束时。
首先需要为所有这些情况创建声音对象。可以把相应代码放在 pygame.mixer.init
之后但在 while
循环之前的任何位置上。
hit_wall = pygame.mixer.Sound(/"hit_wall.wav/")hit_wall.set_volume(0.4)get_point = pygame.mixer.Sound(/"get_point.wav/")get_point.set_volume(0.2)splat = pygame.mixer.Sound(/"splat.wav/")splat.set_volume(0.6)new_life = pygame.mixer.Sound(/"new_life.wav/")new_life.set_volume(0.5)bye = pygame.mixer.Sound(/"game_over.wav/")bye.set_volume(0.6)
这里我选择了不同的音量,这只是为了看看哪种音量听起来最合适。可以按你的喜好来设置音量。另外要记住,所有声音文件都要复制到保存代码的位置上。这些声音都可以在 examplessounds 文件夹或者本书网站上找到。
现在需要在发生这些事件时的相应代码中增加 play
方法。只要碰到窗口左右两边就应当发出 hit_wall
声音。这个事件在球的 move
法中检测,我们还要让球的 x 速度反向(使球在两边“反弹”)。在原来的代码清单 18-5 中,这是第 14 行 (if self.rect.left < 0 or self.rect.right > screen.get_width:
)。
所以,在反向时还可以播放声音。代码如下:
可以对 get_point
声音做同样的处理。在球的 move
方法下面一点点的地方,我们检测了球是否碰到窗口顶边。在这里要让球反弹,并为玩家加 1 分。现在还要播放一个声音。新代码如下:
增加这些代码后,试着运行程序,看看有什么效果。
接下来继续增加代码,当玩家漏球而丢掉一条命时会播放一个声音。这个事件在主 while
循环中检测,也就是原来的代码清单 18-5 中的第 63 行(if myBall.rect.top >= screen.get_rect.bottom:
)。只需再增加这样一行代码:
还可以在新的一条命开始时增加一个声音。这种情况在代码清单 18-5 的最后 3 行代码发生(也就是 else
块中)。这一次我们会在开始新的一条命之前留出一点时间来播放音效:
else:pygame.time.delay(1000)new_life.playmyBall.rect.topleft = [50, 50]screen.blit(myBall.image, myBall.rect)pygame.display.flippygame.time.delay(1000)
与原来的程序不同,现在不是等待 2 秒,我们会等待 1 秒(1000 毫秒),再播放声音,然后在开始下一轮之前再等待 1 秒。可以试试看,听听效果如何。
这里还要增加一个音效:游戏结束时需要播放一个声音。这种情况在代码清单 18-5 的第 65 行发生(if lives == 0:
)。在这里增加下面这行代码,就会播放 bye
声音:
if lives == 0:bye.play
试试看效果如何。
唉呀!我们忘了一件事。播放 bye
声音和 splat
声音的代码放在主 while
循环中,Pygame 窗口关闭前它们是不会停止的,所以只要 while
循环在运行,声音就会反复播放!需要增加一些代码来确保它只会播放一次。
这里就要使用前面定义的 done
变量了,它会告诉我们游戏何时结束。可以把代码修改成下面这样:
试试看,确认程序能正常工作。
嗯……这个问题可能需要稍稍考虑一下。这里通过 done
变量来告诉我们游戏何时结束,利用这一点,我们能够知道什么时候播放 bye
声音,以及什么时候显示最后的分数消息。不过这球在干嘛?
尽管球已经到达窗口底边,但它仍然在不停地移动!球在继续向下走,越走越远,没有什么来阻止它,所以它的 y 值会越来越大。虽然它在屏幕底边的“下面”,我们看不到,但是仍然能够听到它的声音!球仍在移动,所以当球的 x 值变得足够大或者足够小时,它还会在“左右两边”上反弹。这种情况发生在 move
方法中,只要 while
循环在运行,这个方法就会一直运行。
怎么解决这个问题呢?我们可以采用以下几种办法。
游戏结束时把球的速度设置为 [0,0] 来阻止球继续移动。
查看球是否在窗口底边以下,如果是,就不再播放
hit_wall
声音。检查
done
变量,如果游戏已经结束就不再播放hit_wall
声音。
我选择了第二种方法,不过上面这几种方法都能奏效。你可以选择以上的任意一种方法,修改你的代码来解决这个问题。