球碰到球拍時會發出 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
聲音。
我選擇了第二種方法,不過上面這幾種方法都能奏效。你可以選擇以上的任意一種方法,修改你的代碼來解決這個問題。