在這篇博文中,我們準備為打飛機小游戲添加一個暫停的功能,即用戶在游戲過程中隨時可以通過單擊屏幕右上方的一個暫停按鈕來暫停和恢復游戲。這個功能看似比較簡單,但其中涉及了鼠標操作、圖片切換、代碼結構的重置等等,接下來我們一一進行介紹。
1、加載暫停按鈕圖標
在image文件夾下一共有四張暫停按鈕的圖片,分別為深色和淺色兩組,首先在main()函數中加載相關圖片資源并初始化暫停/開始標志位:
~~~
paused = False # 標志是否暫停游戲
pause_nor_image = pygame.image.load("image/game_pause_nor.png") # 加載暫停相關按鈕
pause_pressed_image = pygame.image.load("image/game_pause_pressed.png")
resume_nor_image = pygame.image.load("image/game_resume_nor.png")
resume_pressed_image = pygame.image.load("image/game_resume_pressed.png")
paused_rect = pause_nor_image.get_rect()
paused_rect.left, paused_rect.top = width - paused_rect.width - 10, 10 # 設置暫停按鈕位置
paused_image = pause_nor_image # 設置默認顯示的暫停按鈕
~~~
代碼看起來有點繁瑣,其實每句代碼的功能都十分簡單。先設置一個暫停/開始標志位“paused”,為true表示暫停狀態,為false表示非暫停狀態。然后加載四張圖片,注意這里四張圖片都是由特定含義的,“pause_nor_image”代表未選中狀態下的暫停按鈕, “pause_pressed_image”代表選中狀態下的暫停按鈕,“resume_nor_image”代表未選中狀態下的開始按鈕,“resume_pressed_image”代表選中狀態下的開始按鈕,鼠標移動到按鈕區域按鈕就變為選中狀態。然后創建一個“paused_image”變量用以保存當前需要顯示的按鈕圖片,游戲開始時默認為“pause_nor_image”。注意這里需要事先得到并設置好按鈕圖片的區域位置,在接下來的程序中會用到。
2、定義“選中/未選中”狀態切換
之前已經說過,選中和未選中狀態是由鼠標是否移動到按鈕區域來決定的,因此需要定義鼠標移動的事件響應函數,先上代碼:
~~~
# ====================檢測用戶的退出及暫停操作====================
for event in pygame.event.get(): # 響應用戶的偶然操作
if event.type == QUIT:
# 如果用戶按下屏幕上的關閉按鈕,觸發QUIT事件,程序退出elif event.type == MOUSEMOTION:
if paused_rect.collidepoint(event.pos): # 如果鼠標懸停在按鈕區域
if paused: # r如果當前的狀態是暫停
paused_image = resume_pressed_image
else:
paused_image = pause_pressed_image
else:
if paused:
paused_image = resume_nor_image
else:
paused_image = pause_nor_image
~~~
對于鼠標移動事件,每當鼠標指針的位置坐標發生變化時,都會觸發一次“MOUSEMOTION”事件,在系統接收到鼠標移動事件后,首先要判斷當前鼠標指針是否位于按鈕的矩形區域,這個功能可以通過rect類的的collidepoint()成員函數完成,它能夠實現判斷一個坐標點(例如當前的event.pos)是否在調用者的(一個矩形對象)的區域范圍之內。如果鼠標處于按鈕區域,則將當前顯示的圖片指定為“選中狀態下的開始/暫停”(resume_pressed_image和pause_pressed_image),否則設定為“非選中狀態下的開始/暫停”(resume_nor_image和pause_nor_image),這些小邏輯還是挺磨人的,需要仔細的推敲一把才能理清。
3、定義“暫停/開始”狀態切換
程序的暫停/開始時通過鼠標單擊的動作來決定的,因此需要編寫鼠標單擊事件的響應函數,在函數中修改“paused”標志位的值來控制暫停/開始狀態的切換:
~~~
for event in pygame.event.get(): # 響應用戶的偶然操作
if event.type == QUIT:
# 如果用戶按下屏幕上的關閉按鈕,觸發QUIT事件,程序退出elif event.type == MOUSEBUTTONDOWN:
button_down_sound.play()
if event.button == 1 and paused_rect.collidepoint(event.pos): # 如果檢測到用戶在指定按鈕區域按下鼠標左鍵
paused = not paused
if paused: # r如果當前的狀態是暫停
paused_image = resume_pressed_image
pygame.time.set_timer(supply_timer, 0) # 關閉補給機制以及所有音效
pygame.mixer.music.pause()
pygame.mixer.pause()
else:
paused_image = pause_pressed_image
pygame.time.set_timer(supply_timer, 30 * 1000) # 開啟補給機制以及所有音效
pygame.mixer.music.unpause()
pygame.mixer.unpause()
~~~
簡單分析一下這段代碼:當鼠標按下時(無論是左鍵、右鍵還是中間滾輪)會觸發“MOUSEBUTTONDOWN”事件。程序檢測到鼠標按下的消息事件后,先播放一聲鼠標單擊的音效,然后檢測按鍵順序以及鼠標位置。如果檢測到當前為左鍵單擊(event.button == 1)并且鼠標指針位于按鈕區域之內(paused_rect.collidepoint(event.pos)返回true),則認為用戶發出了有效的暫停指令,此時需要將paused標志位取反。緊接著就需要判斷當前狀態是暫停還是非暫停,如果單擊鼠標之后變為暫停狀態(paused為真),則需要關閉補給機制、關閉背景音效、關閉混音器,將按鈕圖片設置為resume_pressed_image(待開始),讓程序靜靜的等待即可;相反若鼠標單擊之后為開始狀態,則需要重新開啟這些機制,同時調整按鈕圖片為pause_pressed_image(待暫停)。
4、將paused標志位加入到控制語句
在完成了準備階段的工作之后,我們開始讓paused這個控制標志位真正參與到程序的控制結構中。由于之前在添加“life_num”控制變量的過程中已經對程序結構進行了統一調整,這里的工作就變得相對簡單,只需在“life_num”的判斷語句之后加上對paused標志位的判斷即可:
~~~
if life_num and (not paused): # 如果游戲未被暫停,正常運行
~~~
對了,差點忘了在while循環內部繪制暫停按鈕圖標,不過這里繪制操作應該放在“if life_num and (not paused):”判斷語句的控制范圍之外,以便使得無論程序是否暫停,用戶都有圖標可以點擊:
~~~
screen.blit(paused_image, paused_rect)
~~~
OK,程序到這里應該能夠順利運行了,在下一篇博客中我們將為游戲添加最后一個功能:GameOver界面的設置。