在這篇博文里,我們將為我方飛機添加三條生命。
1、加載相關資源
在目前的游戲中,我方飛機是擁有不死生命的,損毀了就在下方復活,這顯然不合邏輯,因此需要為我放飛機增加生命數,并在屏幕右下方顯示對應圖標。首先在main()函數中設置初始化生命數并加載小飛機圖片:
~~~
life_image = pygame.image.load("image/life.png").convert()
life_rect = life_image.get_rect()
life_num = 3 # 一共有三條命
~~~
2、將“life_num”加入程序循環判斷語句中
既然我方飛機擁有了生命屬性,那就意味著我們不能夠再向之前那樣隨意的擺放while()循環中的代碼了,很多代碼在執行前都需要判斷life_num是否為零,比如說發射子彈,我方飛機都已經掛掉了,再發射子彈就顯得不盡合理了吧。
因此我們需要考慮哪些代碼在執行前需要判斷life_num是否為零,具體來說,只要涉及到和精靈有關的操作都應該在life_num > 0時進行,因此我們將下列操作放在life_num的判斷條件之外:(1)打印背景圖片和分數的操作。因為不能因為我方飛機掛掉就讓屏幕一篇漆黑,背景還是應該有的;(2)事件響應機制。因為我方飛機掛掉之后同樣需要響應用戶事件,比如鼠標單擊事件、系統退出事件。除了以上這兩個操作之外,其余操作都應該放在“if life_num:”的條件循環之內,因此可能需要我們將之前的代碼順序做一些調整:
~~~
while running:
# 將背景圖片打印到內存的屏幕上# 檢測用戶的退出及暫停操作
~~~
~~~
if life_num
# 繪制全屏炸彈數量和剩余生命數量# 檢測用戶的鍵盤操作# 繪制補給并檢測玩家是否獲得# 子彈與敵機的碰撞檢測
# 我方飛機碰撞檢測
# 繪制我方飛機# 繪制敵方飛機
# …………………………
~~~
~~~
elif life_num == 0: # 生命值為零,繪制游戲結束畫面
pass
# 將內存中繪制好的屏幕刷新到設備屏幕上
# 設置幀數為60
~~~
3、life_num遞減操作
重新安排完代碼結構后,接下來只需在我方飛機損毀時,將life_num減一:
~~~
if me.active:# 繪制我方飛機的兩種不同的形式else:
if not (delay % 3):
# 繪制我方飛機損毀畫面
if me_destroy_index == 0:
life_num -= 1# 我方飛機重生
~~~
當然這里也用了“me_destroy_index == 0”的限定條件,以保證在損毀期間只減一次生命數(詳見之前博文)。
4、繪制life_num圖標
在游戲過程中,為了顯示當前玩家還有多少生命數,需要通過在屏幕右下方顯示小飛機圖標來指示,玩家當前有幾條命就顯示幾個圖標。小圖標的資源已將在開始時加載好了,我們先給出完整的顯示代碼,稍后解釋:
~~~
for i in range(life_num):
screen.blit(life_image, (width - 10 - (i + 1) * life_rect.width, height - 10 - life_rect.height))
~~~
這里只是做了一些簡單的數學運算,“(width - 10 - (i + 1) * life_rect.width, height - 10 - life_rect.height)”這段代碼就能夠實現根據當前的life_num的值畫出對應數量的小飛機圖標。
5、為我方飛機添加初始化無敵機制
程序編寫到這里貌似已經實現了預期目標,不過其實這里面有一個影藏的BUG,需要多次實現才會出現。因為我方飛機在重生時都是在固定位置出現的,那么就有這樣一種可能性:就是在我方飛機重生時,在屏幕下方正中間(我方飛機重生的位置)正好有一架敵機,這就導致我方飛機一出生就掛掉,根本沒有躲避的事件,雖然這種BUG出現的幾率不大,但我們還是在這里提供一個解決方案,就是讓我方飛機在重生之后具有三秒的無敵時間。因此我方飛機又多了一個屬性:無敵。
首先向我方飛機類的內部添加用來表示當前無敵狀態的標志位:
~~~
self.invincible = False # 飛機初始化時有三秒的無敵時間
~~~
對應的在reset()成員函數中將其置為true:
~~~
self.invincible = True
~~~
接下來我們通過事件觸發系統來設計一個定時器,用以記錄無敵時間,首先在main函數中定義這個計時器:
~~~
invincible_time = USEREVENT + 2 # 接觸我方飛機無敵時間定時器
~~~
由于之前已經定義了兩個用戶事件了(supply_timer,double_bullet_timer),因此這里指定的標號為USEREVENT + 2。
然后在我方飛機reset之后(invincible置為true,無敵狀態開始),激活這個定時器,計時開始(3秒):
~~~
if me.active:# 繪制我方飛機的兩種不同的形式else:
if not (delay % 3):
# 繪制我方飛機損毀畫面
if me_destroy_index == 0:
me.reset() # 我方飛機重生并開始無敵時間計時
pygame.time.set_timer(invincible_time, 3 * 1000)
~~~
激活定時器之后,編寫事件響應函數。若該事件被觸發,說明三秒的無敵時間已過,需要將我方飛機的無敵標志位置為false,并關閉計時器:
~~~
for event in pygame.event.get(): # 響應用戶的偶然操作
if event.type == QUIT:
# 如果用戶按下屏幕上的關閉按鈕,觸發QUIT事件,程序退出elif event.type == invincible_time: # 如果無敵時間已過
me.invincible = False
pygame.time.set_timer(invincible_time, 0)
~~~
最后,我們修改一下我方飛機的碰撞檢測函數,使得當我方飛機與敵機發生碰撞時,只有在我方飛機的invincible變量為false(非無敵狀態)的情況下,才執行我方飛機和敵機的銷毀操作:
~~~
# ====================我方飛機碰撞檢測====================
enemies_down = pygame.sprite.spritecollide(me, enemies, False, pygame.sprite.collide_mask)
if enemies_down and not me.invincible: # 如果碰撞檢測返回的列表非空,則說明已發生碰撞,若此時我方飛機處于無敵狀態
me.active = False
for e in enemies_down:
e.active = False # 敵機損毀
~~~
這里就是在原有的if語句調價的基礎上添加“not me.invincible”判斷,且二者為“與”操作的關系。好的,程序到此就告一段落,順利的實現了預期功能,在下一篇博文中我們在給游戲添加一個暫停的功能。
?