摘要:現在開始創建多行外星人。小結本篇講述了如何在游戲中添加大量相同的元素如何用嵌套循環來創建元素網格如何控制對象在屏幕上移動的方向以及響應事件如何檢測和響應元素碰撞如何在游戲中跟蹤統計信息如何使用標志來判斷游戲是否結束。
《Python編程:從入門到實踐》筆記。1. 回顧項目
本章主要是對上一篇的繼續,添加“外星人”,“外星人”與飛船的交互。
開發較大的項目時,進入每個開發階段前回顧一下開發計劃,搞清楚接下來要通過代碼實現哪些功能至關重要。本篇將設計一下內容:
研究即有代碼,確定實現新功能前是否需要重構代碼
在屏幕左上角添加一個外星人,并指定合適的邊距
根據第一個外星人的邊距和屏幕尺寸計算屏幕上可容納多少個外星人。編寫一個循環來填滿屏幕的上半部分
讓外星艦隊向兩邊和下方移動,直到外星人被全部擊落,或有外星人撞到飛船,或有外星人抵達屏幕底部。如果所有外星人都被擊落,再創建一批外星人。如果有外星人撞到飛船或到達屏幕底部,則銷毀飛船并再創建一群外星人。
限制玩家可用的飛機數,消耗完則游戲結束
希望各位上一篇的代碼沒有刪掉。在開始新的代碼前,我們先在前面的check_keydown_events()函數中添加“通過快捷鍵Q結束游戲”的代碼:
def check_keydown_event(event, ship, ai_settings, screen, bullets): -- snip -- elif event.key == pygame.K_q: sys.exit()2. 創建外星人
首先我們需要編寫一個外星人Alien類。新建alien.py模塊,在其中加入如下代碼:
import pygame from pygame.sprite import Sprite class Alien(Sprite): """表示單個外星人的類""" def __init__(self, ai_settings, screen): """初始化外星人并設置其起始位置""" super(Alien, self).__init__() self.screen = screen self.ai_settings = ai_settings # 加載外星人圖像,并設置其rect屬性 self.image = pygame.image.load("images/alien.bmp") self.rect = self.image.get_rect() # 每個外星人最初都在屏幕左上角附近 self.rect.x = self.rect.width self.rect.y = self.rect.height # 存儲外星人的準確位置 self.x = float(self.rect.x) def blitme(self): """在指定位置繪制外星人""" self.screen.blit(self.image, self.rect)
它和Bullet類一樣繼承自Sprite類。現在開始創建多行外星人。
2.1 修改game_functions.py模塊首先在game_functions.py模塊中添加create_fleet()函數用于創建外星艦隊:
def create_fleet(ai_settings, screen, ship, aliens): """創建外星艦隊""" alien = Alien(ai_settings, screen) # 計算每行能放多少個 number_aliens_x = get_number_aliens_x(ai_settings, alien.rect.width) # 計算能放多少行 number_rows = get_number_rows(ai_settings, ship.rect.height, alien.rect.height) # 嵌套循環創建外星艦隊 for row_number in range(number_rows): for alien_number in range(number_aliens_x): # 創建外星人并將其加入艦隊 create_alien(ai_settings, screen, aliens, alien_number, row_number)
然后我們依次補充下面三個函數(注意各個函數的參數),這三個函數也位于game_functions.py中:
get_number_aliens_x(): 計算一行能放多少個外星人
def get_number_aliens_x(ai_settings, alien_width): """計算每行可容納多少個外星人""" # 左右兩側留出一個外星人的寬度 available_space_x = ai_settings.screen_width - 2 * alien_width # 列間距為一個外星人寬度 number_aliens_x = int(available_space_x / (2 * alien_width)) return number_aliens_x
get_number_rows(): 計算能放多少行外星人
def get_number_rows(ai_settings, ship_height, alien_height): """計算屏幕可容納多少行外星人""" # 可用高度 = 窗口高度 - 上方一個外星人高度 - 下方一個飛船高度 - 兩個外星人高度作為緩沖空間 available_space_y = (ai_settings.screen_height - 3 * alien_height - ship_height) # 行距為一個外星人高度 number_rows = int(available_space_y / (2 * alien_height)) return number_rows
create_alien(): 創建外星人
def create_alien(ai_settings, screen, aliens, alien_number, row_number): """創建一個外星人并將其放在當前行""" alien = Alien(ai_settings, screen) # 下面就是根據上面的公式計算每一個外星人在窗口中的位置(這是左上角的坐標) alien.x = alien.rect.width * (1 + 2 * alien_number) alien.rect.x = alien.x alien.rect.y = alien.rect.height * (1 + 2 * row_number) aliens.add(alien)
現在我們還需要修改update_screen()函數:
def update_screen(ai_settings, screen, ship, bullets, aliens): -- snip -- # 繪制外星人,放在繪制子彈的代碼后面,讓外星人的圖像覆蓋掉子彈的圖像 aliens.draw(screen) -- snip --
注意,該函數增加了一個參數aliens,這是個Group對象,所以代碼中的draw()方法也跟前一篇中的bullets.update()方法一樣,一行代碼更新所有對象。
2.2 修改alien_invasion.py模塊在主程序中添加創建外星人的代碼:
def run_game(): -- snip -- gf.create_fleet(ai_settings, screen, ship, aliens) while True: -- snip -- # 比之前代碼多傳入了一個aliens參數 gf.update_screen(ai_settings, screen, ship, bullets, aliens) -- snip --
現在我們執行程序將會得到如下結果:
3. 讓外星艦隊動起來我們將讓外星艦隊在窗體中向右移動,撞到屏幕邊緣后下以一定距離下降,再沿反方向移動,直到外星人被消滅,或外星人撞上飛船,或有外星人到達窗體底部。
3.1 補充settings.py模塊class Settings: def __init__(self): -- snip -- self.fleet_drop_speed = 10 # 外星艦隊方向標志:1向右,-1向左 # 也可以用如left, right之類的標志,但這樣會很麻煩 self.fleet_direction = 13.2 修改alien.py模塊
我們需要在Alien類中添加兩個方法,一個用于檢測窗體邊緣,一個用于更新Alien對象:
class Alien(Sprite): -- snip -- def check_edges(self): """如果外星人位于屏幕邊緣則返回True""" screen_rect = self.screen.get_rect() return self.rect.right >= screen_rect.right or self.rect.left <= 0 def update(self): """向右移動外星人""" # 以后這樣的方式會用的很多 self.x += self.ai_settings.alien_speed_factor * self.ai_settings.fleet_direction self.rect.x = self.x
如果使用文本值來控制方向,那就需要添加if-else語句來檢測艦隊移動方向。鑒于只有兩個可能的方向,這里使用-1和1來表示,這樣更容易改變外星人對象的坐標。
3.3 修改game_functions.py模塊首先,我們在該模塊中添加一個更新外星艦隊的函數update_aliens():
def update_aliens(ai_settings, aliens): """檢查是否有外星人位于屏幕邊緣,并更新外星艦隊中所有外星人的位置""" check_fleet_edges(ai_settings, aliens) aliens.update() # “一鍵更新”
check_fleet_edges()函數用于檢測艦隊是否碰到了窗體邊緣,代碼如下:
def check_fleet_edges(ai_settings, aliens): """有外星人到達邊緣時采取相應的措施""" # 檢測艦隊中每一個外星人是否碰到了窗體邊緣 for alien in aliens.sprites(): if alien.check_edges(): change_fleet_direction(ai_settings, aliens) break
change_fleet_direction()函數用于改變艦隊的移動方向,以及讓艦隊向下移動,代碼如下:
def change_fleet_direction(ai_settings, aliens): """將外星艦隊下移,并改變它們的方向""" for alien in aliens.sprites(): alien.rect.y += ai_settings.fleet_drop_speed ai_settings.fleet_direction *= -1
上面三個函數就是在game_functions.py中的所有變動。
3.4 修改alien_invasion.py模塊在該模塊中我們只需要在while循環中添加一行代碼:
# 開始游戲的主循環 while True: gf.check_events(ai_settings, screen, ship, bullets) ship.update() gf.update_bullets(bullets) # 添加對外星艦隊的修改 gf.update_aliens(ai_settings, aliens) gf.update_screen(ai_settings, screen, ship, bullets, aliens)
最后運行主程序,得到如下效果:
截了一張靜態圖,實際是動態的。
4. 擊殺外星人對于當前的程序,如果發射子彈,子彈將穿過外星人,而不是擊殺,下面我們繼續完善該項目,使其能擊殺外星人。而要實現這一點,關鍵就是要檢測到子彈圖像與外星人圖像是否重疊,重疊了則表示擊中。
4.1 修改game_functions.py為何檢測子彈與衛星人的碰撞,我們需要修改update_bullets()函數,這里我們增加了update_bullets()的參數,還調用了一個新函數:
def update_bullets(bullets, aliens, ship, screen, ai_settings): -- snip -- check_bullet_alien_collisions(ai_settings, screen, ship, aliens, bullets)
函數check_bullet_alien_collisions()用于檢測子彈與外星人的碰撞,當外星人被消滅光時,清空現有子彈,并生成新的外星艦隊,它的代碼如下:
def check_bullet_alien_collisions(ai_settings, screen, ship, aliens, bullets): """檢測是否有子彈擊中了外星人,如果有,就刪除相應的子彈和外星人""" # 下一篇中我們將用該變量實現分數統計 collisions = pygame.sprite.groupcollide(bullets, aliens, True, True) #如果外星人被消滅光,則生成新的外星人艦隊 if len(aliens) == 0: # 刪除現有的子彈并創建新的艦隊 bullets.empty() create_fleet(ai_settings, screen, ship, aliens)
sprite.groupcollide()方法用于檢測對象之間的碰撞,它將bullets中的每個子彈的rect與aliens中的每個外星人的rect進行比較,并返回一個字典。該字典以第一個參數中的對象為鍵,以第二個參數中的鍵為值,在這里,以bullets中發生了碰撞的bullet為鍵,它的值為與之碰撞的alien(不是aliens)!第三個參數表示是否刪除第一個參數中發生了碰撞的對象,而四個參數表示是否刪除第二個參數中發生了碰撞的對象。
4.2 修改alien_invasion.py只需要修改調用update_bullets()函數的那行代碼即可,增加幾個參數:
gf.update_bullets(bullets, aliens, ship, screen, ai_settings)
基礎功能基本完成。
4.3 測試技巧補充對于上述代碼,我們可能需要測試當消滅完外星人后,新的艦隊是否能被正確創建等,如果我們以現在游戲的設定,即子彈速度為1,子彈寬度為3,那測試起來將會很痛苦。此時,我們可以修改修改游戲的參數,比如將子彈寬度修改為300,子彈速度修改為3,這樣就相當于對游戲進行了快進,此時代碼的運行效果如下:
不過最后記得將參數修改回去。
5. 結束游戲接下來我們實現外星人碰到飛船,外星人抵達窗體底部,飛船數用光導致游戲結束的代碼。
5.1 創建GameStats類首先我們創建一個用于存儲游戲信息的GameStats類,存放在game_stats.py文件中:
class GameStats: """跟蹤游戲的統計信息""" def __init__(self, ai_settings): """初始化統計信息""" # 用于控制游戲啟動與否 self.game_active = True self.ai_settings = ai_settings self.reset_stats() def reset_stats(self): """初始化在游戲運行期間可能變化的統計信息""" # 重置飛船數 self.ships_left = self.ai_settings.ship_limit5.2 修改settings.py
從上述代碼可以看出,我們需要在settings.py中添加一項表示“飛船數”的信息:
class Settings: def __init__(self): """初始化游戲的設置""" # 屏幕設置 -- snip -- # 設置飛船數量限制 self.ship_limit = 3 -- snip --5.3 響應飛船與外星人的碰撞,修改game_functions.py
我們在更新每個外星人的位置后立即檢測外星人和飛船之間的碰撞,隨后再檢查外星人是否到達了窗體底部。修改update_aliens()函數,使用sprite中的spritecollideany()方法來檢測碰撞:將第二參數中的每一個元素與第一個參數比較,檢測是否碰撞,返回第二個參數中第一個發生碰撞的對象,如果沒有發生碰撞則返回None:
# 增加了參數和碰撞檢測 def update_aliens(ai_settings, aliens, ship, screen, bullets, stats): -- snip -- # 檢測外星人和飛船之間的碰撞 if pygame.sprite.spritecollideany(ship, aliens): ship_hit(ai_settings, stats, screen, ship, aliens, bullets) check_aliens_bottom(ai_settings, stats, screen, ship, aliens, bullets)
為此我們需要增加兩個函數:
ship_hit():當外星人與飛船發生碰撞時,調用次函數
-- snip -- from time import sleep def ship_hit(ai_settings, stats, screen, ship, aliens, bullets): """響應被外星人撞到的飛船""" # 將ship_left減1 if stats.ships_left > 0: stats.ships_left -= 1 # 清空外星人列表和子彈列表 aliens.empty() bullets.empty() # 創建一群新的外星人,并將飛船恢復到初始位置 create_fleet(ai_settings, screen, ship, aliens) ship.center_ship() # 暫停 sleep(0.5) else: stats.game_active = False
從上面的代碼還可以看出,我們還需要在Ship類中添加一個center_ship()方法:
def center_ship(self): """讓飛船在屏幕上居中""" self.center = self.screen_rect.centerx
check_aliens_bottom(): 當飛船到達窗體底部時調用次函數
def check_aliens_bottom(ai_settings, stats, screen, ship, aliens, bullets): """檢測是否有外星人到達了屏幕底部""" screen_rect = screen.get_rect() for alien in aliens.sprites(): if alien.rect.bottom >= screen_rect.bottom: # 和飛船被碰撞是的代碼沒啥區別,故調用同一個函數 ship_hit(ai_settings, stats, screen, ship, aliens, bullets) break5.4 修改主程序alien_invasion.py
修改游戲的循環部分:
# 開始游戲的主循環 while True: gf.check_events(ai_settings, screen, ship, bullets) # 決定程序運行時該執行的部分 if stats.game_active: ship.update() gf.update_bullets(bullets, aliens, ship, screen, ai_settings) gf.update_aliens(ai_settings, aliens, ship, screen, bullets, stats) gf.update_screen(ai_settings, screen, ship, bullets, aliens)
在主循環中,任何情況下都需要調用check_events(),即使游戲處于非活動狀態;還需要不斷更新屏幕,以便在等待玩家是否選擇重新開始游戲時能夠修改屏幕;其他函數僅在游戲處于活動狀態時太需要調用。
6. 小結本篇講述了:
如何在游戲中添加大量相同的元素;
如何用嵌套循環來創建元素網格;
如何控制對象在屏幕上移動的方向以及響應事件;
如何檢測和響應元素碰撞;
如何在游戲中跟蹤統計信息;
如何使用標志game_active來判斷游戲是否結束。
下一篇中,同時也是本項目的最后一篇,我們將:
添加一個Play按鈕讓玩家能夠開始游戲,以及游戲結束后再開始;
每當玩家消滅一群外星人后,加快游戲節奏;
添加一個分數系統。
迎大家關注我的微信公眾號"代碼港" & 個人網站 www.vpointer.net ~
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/41789.html
摘要:本章主要介紹字典的概念,基本操作以及一些進階操作。使用字典在中,字典是一系列鍵值對。中用花括號來表示字典。代碼定義空字典的語法結果如果要修改字典中的值,只需通過鍵名訪問就行。 《Python編程:從入門到實踐》筆記。本章主要介紹字典的概念,基本操作以及一些進階操作。 1. 使用字典(Dict) 在Python中,字典是一系列鍵值對。每個鍵都與一個值相關聯,用鍵來訪問值。Python中用...
摘要:和標志,用于表示飛船是否正在移動,用于實現飛船在不松開按鍵下連續移動。重寫了函數,用于繪制飛船模塊該模塊主要是集中處理游戲中發生的各種事件。函數用于監聽游戲的事件,比如,它表示游戲推出事件和分別表示鍵盤按下與松開事件。 《Python編程:從入門到實踐》筆記。本章主要學習如何使用pygame編寫一個簡單的小飛機打外星人的游戲,由于本人對用python寫游戲并不是特別感興趣,所以主要是看...
摘要:之所以這里要添加這四行代碼,其實是為了當你重新開始也就是第二次及以后點擊按鈕游戲時,計分板能正確顯示。當第一運行游戲時,沒有這四行也能正確顯示計分板。 《Python編程:從入門到實踐》筆記。本篇是Python小游戲《外星人入侵》的最后一篇。 1. 前言 本篇我們將結束Pygame小游戲《外星人入侵》的開發。在本篇中,我們將添加如下內容: 添加一個Play按鈕,用于根據需要啟動游戲以...
摘要:年云棲大會在杭州舉行,據主辦方介紹本次云棲大會吸引了五萬多人參會,但是在密集的會議中又有哪些亮點值得關注領導致辭很無聊每次重要的大會,都離不開一些政府要員們的參與,但是在高新技術的互聯網,云計算,大數據領域真心不敢恭維,除了讓整個會議前半場 2016年云棲大會在杭州舉行,據主辦方介紹本次云棲大會吸引了五萬多人參會,但是在密集的會議中又有哪些亮點值得關注?領導致辭很無聊每次重要的大會,都離不開...
摘要:前言喵星人真的是要統治世界了。完整的代碼如下所示效果如下我們選擇這位顏值高的喵星人代碼測試效果要測試代碼,只需使用您選擇的工具運行它。 ?前言 ? ? ?喵星人真的是要統治世界了。?不然為什么OpenCV自帶的檢測器中除了人臉檢測、行人檢測 這些意料之中就應該存在的檢測器之外,還悄悄多出了貓...
閱讀 3141·2023-04-26 02:33
閱讀 3102·2023-04-25 21:33
閱讀 907·2021-09-02 09:56
閱讀 2910·2019-08-30 15:44
閱讀 2460·2019-08-30 13:15
閱讀 1034·2019-08-30 13:04
閱讀 1634·2019-08-29 15:09
閱讀 3956·2019-08-26 18:26