首页 » 与孩子一起学编程 » 与孩子一起学编程全文在线阅读

《与孩子一起学编程》19.7 更多声音

关灯直达底部

球碰到球拍时会发出 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 中,这是第 15 行 (if self.rect.left < 0 or self.rect.right > screen.get_width:)。SPE 中可以看到编辑器窗口左边会显示出行号。

所以,在反向时还可以播放声音。代码如下:

可以对 get_point 声音做同样的处理。在球的 move 方法下面一点点的地方,我们检测了球是否碰到窗口顶边。在这里要让球反弹,并为玩家加 1 分。现在还要播放一个声音。新代码如下:

增加这些代码后,试着运行程序,看看有什么效果。

接下来继续增加代码,当玩家漏球而丢掉一条命时会播放一个声音。这个事件在主 while 循环中检测,也就是原来的代码清单 18-5 中的第 67 行(if myBall.rect.top >= screen.get_rect.bottom:)。只需再增加这样一行代码:

还可以在新的一条命开始时增加一个声音。这种情况在代码清单 18-5 的最后 3 行代码发生(也就是 else 块中)。这一次我们会在开始新的一条命之前留出一点时间来播放音效:

else:   pygame.time.delay(1000)   new_life.play   myBall.rect.topleft = [50, 50]   screen.blit(myBall.image, myBall.rect)   pygame.display.flip   pygame.time.delay(1000)

与原来的程序不同,现在不是等待 2 秒,我们会等待 1 秒(1000 毫秒),再播放声音,然后在开始下一轮之前再等待 1 秒。可以试试看,听听效果如何。

这里还要增加一个音效:游戏结束时需要播放一个声音。这种情况在代码清单 18-5 的第 69 行发生(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 声音。

我选择了第二种方法,不过上面这几种方法都能奏效。你可以选择以上的任意一种方法,修改你的代码来解决这个问题。