用 python 写游戏《外星人入侵》:限制飞船的活动范围并给飞船增加射击功能
文章目錄
- 限制飛船的活動范圍
- 重構 check_events()
- 小結
- alien_invasion.py
- settings.py
- game_funcations.py
- ship.py
- 射擊
- 添加子彈設置
- 創建 Bullet 類
- 將子彈存儲到編組中
- 開火
- 刪除已消失的子彈
- 限制子彈數量
- 創建函數 update_bullets()
- 創建函數 fire_bullet()
限制飛船的活動范圍
當前,如果玩家按住箭頭鍵的時間足夠長,飛船將移到屏幕外面,消失得無影無蹤。下面來修復這種問題,讓飛船到達屏幕邊緣后停止移動。為此,我們將修改 ship類的方法 update():
def update(self):#根據移動標志調整飛船的位置#更新飛船的centerx值,而不是rectif self.moving_right and self.rect.right < self.screen_rect.right:self.center += self.ai_settings.ship_speed_factor if self.moving_left and self.rect.left > 0:self.center -= self.ai_settings.ship_speed_factor #根據self.center更新rect值self.rect.centerx = self.center上述代碼在修改 self.center 的值之前檢查飛船的位置。self.rect.right 返回飛船外接矩形的有邊緣的x坐標,如果這個值小于self.screen_rect.right 的值,就說明飛船未觸及屏幕右邊緣。左邊緣的情況與此類似:如果rect的左邊緣的x坐標大于零,就說明飛船未觸及屏幕左邊緣。這確保僅當飛船在屏幕內時,才調整 self.center 的值。
如果此時 alien_invasion.py,飛船將在觸及屏幕左邊緣或右邊緣后停止移動。
重構 check_events()
隨著游戲開發的進行,函數 check_events() 將越來越長,我們將其部分代碼放在兩個函數中:
一個負責處理KEYDOWN事件,另一個處理 KEYUP事件:
小結
項目到此,我們完成了窗口繪制,飛船繪制和位置設置。還設置了飛船的移動速度,讓其進行到一定程度時加快游戲節奏,當然,還有飛船的左右移動。我們一共創建了四個模塊。下面我們來總結一下四個模塊的分別作用:
alien_invasion.py
主文件創建一系列整個游戲都要使用的對象:存儲在 ai_settings中的設置、存儲在 screen中的
surface以及一個飛船實例。文件 alien_invasion還包含游戲的主循環,這是一個調用
check_events()、ship.update()和update_screen()的while循環。
要啟動《外星人入侵》,只需運行文件alien_invasion.py。其他文件(settings.py、game_functions.py、ship.py)包含的代碼被直接或間接地導入到這個文件中。
settings.py
文件 settings.py包含Settings類,這個類只包含 __ init __(),它負責初始化控制游戲外觀和飛船速度的屬性。
game_funcations.py
該文件包含一系列函數,游戲的大部分工作都是由它們完成的。函數check_events()檢測相關的事件,如松鍵或按鍵,并使用輔助函數
check_keydown_events()和check_keyup_events()來處理事件。就目前而言,這些函數管理飛船的移動。模塊game_functions還包含
update_screen(),它用于在每次執行主循環時都重繪屏幕。
ship.py
該文件包含 Ship類,這個類包含方法 __ init __(),管理飛船位置的方法 update()以及在屏幕上繪制飛船的方法
blitme()。表示飛船的圖像存儲在文件夾 images下的ship.bmp中。
射擊
下面我們來給飛船增加射擊功能,我們將編寫玩家按空格鍵時發射子彈(小矩形)的代碼。子彈將在屏幕中向上穿行,抵達屏幕邊緣后消失。
添加子彈設置
首先,更新 settings.py,在其方法__ init __() 末尾存儲新類 Bullet所需的值:
self.bullet_speed_factor = 1self.bullet_width = 3self.bullet_height = 15self.bullet_color = 60,60,60創建 Bullet 類
這里我們創建存儲 Bullet類的文件 bullet.py,其前半部分如下:
import pygame from pygame.sprite import Spriteclass Bullet(Sprite):#一個對飛船發射子彈管理的類def __init__(self,ai_settings,screen,ship):#在飛船所處位置創建一個子彈對象super(Bullet,self).__init__()self.screen = screen#在(0,0)處創建一個表示子彈的矩形,再設置正確的位置self.rect = pygame.Rect(0,0,ai_settings.bullet_width,ai_settings.bullet_height)self.rect.centerx = ship.rect.centerxself.rect.top = ship.rect.top#存儲用小數表示的子彈位置self.y = float(self.rect.y)self.color = ai_settings.bullet_colorself.speed_factor = ai_settings.bullet_speed_factorBullet類繼承了我們從模塊pygame.sprite中導入的Sprite類。通過使用精靈,可將游戲中相關的元素編組,進而同時操作編組中的所有元素。為創建子彈實例,需要向__ init __ ()傳遞ai_settings、screen和ship實例,還調用了super()來繼承Sprite
code 說明
self.rect = pygame.Rect(0,0,ai_settings.bullet_width,ai_settings.bullet_height)
創建子彈的屬性rect。子彈并非基于圖像的,因此我們必須使用pygame.Rect()類從空白開始創建一個矩形。創建這個類的實例時,必須提供矩形左上角的x坐標和y坐標,還有矩形的寬度和高度。我們在(0,0)處創建這個矩形,但接下來的兩行代碼將其移到了正確的位置,因為子彈的初始位置取決于飛船當前的位置。子彈的官渡和高度是從ai_settings中獲取的。
self.rect.centerx = ship.rect.centerx
self.rect.top = ship.rect.top
我們將子彈的centerx設置為飛船的rect.centerx。子彈應從飛船頂不射出,因此我們將表示子彈的rect的top屬性設置為飛船的rect的top屬性,讓子彈看起來像是從飛船中射出的。
#存儲用小數表示的子彈位置
self.y = float(self.rect.y)
self.color = ai_settings.bullet_color
self.speed_factor = at_settings.bullet_speed_factor
我們將子彈的y坐標存儲為小數值,以便能夠微調子彈的速度。然后將子彈的顏色和速度分別設置存儲到self.color和self.speed_factor中。
下面是bullet.py的第二部分----方法update()和draw_bullet():
def update(self):#向上移動子彈#更新表示子彈位置的小數值self.y -= self.speed_factorself.rect.y = self.ydef draw_bullet(self):#在屏幕上繪制子彈pygame.draw.rect(self.screen,self.color,self.rect)方法update()管理子彈的位置。發射出去后,子彈在屏幕中向上移動,這意味著y坐標將不斷減小,因此為更新子彈的位置,我們從self.y中減去self.speed_factor的值。接下來,我們將self.rect.y設置為 self.y的值。屬性speed_factor讓我們能夠隨著游戲的進行或根據需要提高子彈的速度,以調整游戲的行為。子彈發射后,其x坐標始終不變,因此子彈將沿直線垂直地往上穿行。
在需要繪制子彈時,我們調用draw_bullet()。函數draw.rect()使用存儲在self.color中的顏色填充表示子彈的rect占據的屏幕部分。
將子彈存儲到編組中
定義Bullet類和必要的設置后,我們就可以編寫代碼了。
在玩家每次按空格鍵時都射出一發子彈。
首先,我們將在alien_invasion.py中創建一個編組(group),用于存儲所有有效的子彈,以便能夠管理發射出去的所有子彈。這個編組將是pygame.sprite.Group類的一個實例;pygame.sprite.Group類類似于列表,但提供了有助于開發游戲的額外功能。在主循環中,我們將使用這個編組在屏幕上繪制子彈,以及更新每顆子彈的位置:
from pygame.sprite import Group #創建一個用于存儲子彈的編組bullets = Group()# while 循環來控制游戲 while True:gf.check_events(ai_settings,screen,ship,bullets)ship.update()bullets.update() gf.update_screen(ai_settings,screen,ship,bullets)在這里我們導入pygame.sprite中的Group類。
這個編組是在while循環外面創建的,這樣就無需每次運行該循環時都創建一個新的子彈編組。
將bullets傳遞給了check_events()和update_screen(),在check_events()中,需要在玩家按空格鍵時處理bullets;而在update_screen()中,需要更新要繪制到屏幕上的bullets。
當你對編組調用update()時,編組將自動對其中的每個精靈調用update(),因此代碼行bullest.update()將為編組bullest中的每顆子彈調用bullet.update()
開火
在game_funcations.py中:
我們需要修改check_keydown_events(),以便在玩家按空格鍵時發射一顆子彈。我們無需修改check_keyup_events(),因為玩家松開空格鍵時什么都不會發生。我們還需要修改update_screen(),確保在調用flip()前在屏幕上重繪每顆子彈。
from bullet import Bulletdef check_keydown_events(event,ai_settings,screen,ship,bullets):if event.key == pygame.K_RIGHT:ship.moving_right = Trueelif event.key == pygame.K_LEFT:ship.moving_left = Trueelif event.key == pygame.K_SPACE:#創建一顆子彈,并將其加入到編組bullets中new_bullet = Bullet(ai_settings,screen,ship)bullets.add(new_bullet)def check_events(ai_settings,screen,ship,bullets):for event in pygame.event.get():if event.type == pygame.QUIT:sys.exit()elif event.type == pygame.KEYDOWN:check_keydown_events(event,ai_settings,screen,ship,bullets)elif event.type == pygame.KEYUP:check_keyup_events(event,ship)def update_screen(ai_settings,screen,ship,bullets):#每次循環時都重繪屏幕screen.fill(ai_settings.bg_color)#在飛船和外星人后面重繪所有子彈for bullet in bullets.sprites():bullet.draw_bullet()ship.blitme()#讓最近繪制的屏幕可見pygame.display.flip()編組bullets傳遞給了check_keydown_events():
玩家按空格鍵時,創建一顆新子彈:new_bullet的Bullet實例,并使用方法add()將其加入到編組bulllets中;代碼bullet.add(new_bullet)將新子彈存儲到編組bullets中。
在check_events()的定義中,我們需要添加形參bullets;調用check_keydown_events()時,我們也需要將bullets作為實參傳遞給它。
def update_screen(ai_settings,screen,ship,bullets):
我們給在屏幕上繪制子彈的update_screen()添加了形參bullets。方法bullets.sprites()返回一個列表,其中包含編組bullets中的所有精靈。為在屏幕上繪制發射的所有子彈,我們遍歷編組bullets中的所有精靈,并對每個精靈都調用draw_bullet()
如果此時運行alien_invasion.py,將能夠左右移動飛船,并發射任意數量的子彈。子彈會在屏幕中向上穿行,抵達屏幕頂步后消失
我們可以在settings.py中修改子彈的尺寸、顏色和速度。
刪除已消失的子彈
當前,子彈抵達屏幕頂端后消失,這僅僅是因為pygame無法在屏幕外面繪制它們。這些子彈實際上依然存在,它們的y坐標為負數,且越來越小。這是一個問題,因為它們將繼續消耗內存和處理能力。
所以我們需要將這些已消失的子彈刪除,否則游戲所做的無謂工作將越來越多,進而變得越來越慢。
檢測這樣的條件,即表示子彈的rect的bottom屬性為零,它表名子彈已穿過屏幕頂端:
alien_invasion.py
在for循環中,不應從列表或編組中刪除條目,因此必須遍歷編組的副本。
我們使用方法copy()設置for循環,這讓我們能夠在for循環中修改bullets。我們檢查每顆子彈,看看它是否已從屏幕頂部消失。如果是這樣,就將其從bullets中刪除。
print()語句用來顯示當前子彈還有多少顆,從而核實已消失的子彈確實刪除了。
.
如果代碼最后沒有問題,確認子彈可以正常刪除,我們將print語句刪除,如果留下這條語句,游戲的速度將大大降低,因為將輸出寫入到終端而花費的時間比將圖形繪制到游戲窗口花費的時間還多。
限制子彈數量
很多射擊游戲都對可同時出現在屏幕上的子彈數量進行限制,以鼓勵玩家有目標地射擊。下面我們也加入同樣的限制。
首先,在 settings.py中存儲允許的最大子彈數:
self.bullets_allowed = 3將未消失的子彈限制為3顆。
在game_functions.py的check_keydown_events()中,我們在創建新子彈前檢查未消失的子彈數是否小于該設置:
玩家按空格時,我們檢查bullets的長度,如果len(bullets)小于3,我們就創建一個新子彈;但如果已有3顆未消失的子彈,則玩家按空格鍵時什么都不發生。如果你現在運行這個游戲,屏幕上最多只能有3顆子彈。
創建函數 update_bullets()
編寫并檢查子彈管理代碼后,可將其移動模塊
game_functions中,以讓主程序文件alien_invasion.py盡可能簡單,我們創建一個名為
update_bullets()的新函數,并將其添加到game_functions.py的末尾。
這個函數中的代碼是從 alien_invasion.py 剪切粘貼過來的,它只需要一個參數,即編組bullets。
alien_invasion.py中的while循環又變得很簡單了:
# while 循環來控制游戲while True:gf.check_events(ai_settings,screen,ship,bullets)ship.update()bullets.update()gf.update_bullets(bullets) gf.update_screen(ai_settings,screen,ship,bullets)我們讓主循環包含盡可能少的代碼,這樣只要看函數名就能迅速知道游戲中發生的情況。主循環檢查玩家的輸入,然后更新飛船的位置和所有未消失的子彈的位置。接下來,我們使用更新后的位置來繪制新屏幕。
創建函數 fire_bullet()
下面將發射子彈的代碼移到一個獨立的函數中,這樣,
在check_keydown_events()中只需使用一行代碼來發射子彈,讓elif代碼變得飛船簡單。
函數 fire_bullet() 只包含玩家按空格鍵時用于發射子彈的代碼;
在check_keydown_events()中,我們在玩家按空格鍵時調用 fire_bullet()。
總結
以上是生活随笔為你收集整理的用 python 写游戏《外星人入侵》:限制飞船的活动范围并给飞船增加射击功能的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: (附源码)计算机毕业设计SSM交通事故记
- 下一篇: matlab去雾处理是视频,一种快速视频