目錄
第13 章
外星人
13.1 回顧項(xiàng)目
game_functions.py
13.2 創(chuàng)建第一個(gè)外星人
13.2.1 創(chuàng)建 Alien 類(lèi)
alien.py
13.2.2 創(chuàng)建 Alien 實(shí)例
alien_invasion.py
13.2.3 讓外星人出現(xiàn)在屏幕上
game_functions.py
13.3 創(chuàng)建一群外星人
13.3.1 確定一行可容納多少個(gè)外星人
注意
13.3.2 創(chuàng)建多行外星人
alien_invasion.py
game_functions.py
13.3.3 創(chuàng)建外星人群
game_functions.py
注意
第13 章
外星人
13.1 回顧項(xiàng)目
開(kāi)發(fā)較大的項(xiàng)目時(shí),進(jìn)入每個(gè)開(kāi)發(fā)階段前回顧一下開(kāi)發(fā)計(jì)劃,搞清楚接下來(lái)要通過(guò)編寫(xiě)代碼 來(lái)完成哪些任務(wù)都是不錯(cuò)的主意。本章涉及以下內(nèi)容。
? 研究既有代碼,確定實(shí)現(xiàn)新功能前是否要進(jìn)行重構(gòu)。
? 在屏幕左上角添加一個(gè)外星人,并指定合適的邊距。
? 根據(jù)第一個(gè)外星人的邊距和屏幕尺寸計(jì)算屏幕上可容納多少個(gè)外星人。我們將編寫(xiě)一個(gè) 循環(huán)來(lái)創(chuàng)建一系列外星人,這些外星人填滿(mǎn)了屏幕的上半部分。
? 讓外星人群向兩邊和下方移動(dòng),直到外星人被全部擊落,有外星人撞到飛船,或有外星 人抵達(dá)屏幕底端。如果整群外星人都被擊落,我們將再創(chuàng)建一群外星人。如果有外星人 撞到了飛船或抵達(dá)屏幕底端,我們將銷(xiāo)毀飛船并再創(chuàng)建一群外星人。
? 限制玩家可用的飛船數(shù)量,配給的飛船用完后,游戲結(jié)束。
我們將在實(shí)現(xiàn)功能的同時(shí)完善這個(gè)計(jì)劃,但就目前而言,該計(jì)劃已足夠詳盡。
在給項(xiàng)目添加新功能前,還應(yīng)審核既有代碼。每進(jìn)入一個(gè)新階段,通常項(xiàng)目都會(huì)更復(fù)雜,因 此最好對(duì)混亂或低效的代碼進(jìn)行清理。
我們?cè)陂_(kāi)發(fā)的同時(shí)一直不斷地重構(gòu),因此當(dāng)前需要做的清理工作不多,但每次為測(cè)試新功能而運(yùn)行這個(gè)游戲時(shí),都必須使用鼠標(biāo)來(lái)關(guān)閉它,這太討厭了。下面來(lái)添加一個(gè)結(jié)束游戲的快捷鍵Q:
game_functions.py
def check_keydown_events(event, ai_settings, screen, ship, bullets):
--snip--
elif event.key == pygame.K_q:
sys.exit()
在check_keydown_events()中,我們添加了一個(gè)代碼塊,以便在玩家按Q時(shí)結(jié)束游戲。這樣 的修改很安全,因?yàn)镼鍵離箭頭鍵和空格鍵很遠(yuǎn),玩家不小心按Q鍵而導(dǎo)致游戲結(jié)束的可能性不 大?,F(xiàn)在測(cè)試時(shí)可按Q關(guān)閉游戲,而無(wú)需使用鼠標(biāo)來(lái)關(guān)閉窗口了。
13.2 創(chuàng)建第一個(gè)外星人
在屏幕上放置外星人與放置飛船類(lèi)似。每個(gè)外星人的行為都由Alien類(lèi)控制,我們將像創(chuàng)建 Ship類(lèi)那樣創(chuàng)建這個(gè)類(lèi)。出于簡(jiǎn)化考慮,我們也使用位圖來(lái)表示外星人。你可以自己尋找表示外 星人的圖像,也可使用圖13-1所示的圖像,可在本書(shū)配套資源(https://www.nostarch.com/ pythoncrashcourse/)中找到。這幅圖像的背景為灰色,與屏幕背景色一致。請(qǐng)務(wù)必將你選擇的圖 像文件保存到文件夾images中。
13.2.1 創(chuàng)建 Alien 類(lèi)
下面來(lái)編寫(xiě)Alien類(lèi):
alien.py
import pygame
from pygame.sprite import Sprite
class Alien(Sprite):
"""表示單個(gè)外星人的類(lèi)"""
def __init__(self, ai_settings, screen):
"""初始化外星人并設(shè)置其起始位置"""
super(Alien, self).__init__()
self.screen = screen
self.ai_settings = ai_settings
# 加載外星人圖像,并設(shè)置其rect屬性
self.image = pygame.image.load('images/alien.bmp')
self.rect = self.image.get_rect()
# 每個(gè)外星人最初都在屏幕左上角附近
1 self.rect.x = self.rect.width
self.rect.y = self.rect.height
# 存儲(chǔ)外星人的準(zhǔn)確位置
self.x = float(self.rect.x)
def blitme(self):
"""在指定位置繪制外星人"""
self.screen.blit(self.image, self.rect)
除位置不同外,這個(gè)類(lèi)的大部分代碼都與Ship類(lèi)相似。每個(gè)外星人最初都位于屏幕左上 角附近,我們將每個(gè)外星人的左邊距都設(shè)置為外星人的寬度,并將上邊距設(shè)置為外星人的高 度(見(jiàn)1)。
13.2.2 創(chuàng)建 Alien 實(shí)例
下面在alien_invasion.py中創(chuàng)建一個(gè)Alien實(shí)例:
alien_invasion.py
--snip--
from ship import Ship
from alien import Alien
import game_functions as gf
def run_game():
--snip--
# 創(chuàng)建一個(gè)外星人
alien = Alien(ai_settings, screen)
# 開(kāi)始游戲主循環(huán)
while True:
gf.check_events(ai_settings, screen, ship, bullets)
ship.update()
gf.update_bullets(bullets)
gf.update_screen(ai_settings, screen, ship, alien, bullets)
run_game()
在這里,我們導(dǎo)入了新創(chuàng)建的Alien類(lèi),并在進(jìn)入主while循環(huán)前創(chuàng)建了一個(gè)Alien實(shí)例。我們 沒(méi)有修改外星人的位置,因此該while循環(huán)沒(méi)有任何新東西,但我們修改了對(duì)update_screen()的 調(diào)用,傳遞了一個(gè)外星人實(shí)例。
13.2.3 讓外星人出現(xiàn)在屏幕上
為讓外星人出現(xiàn)在屏幕上,我們?cè)趗pdate_screen()中調(diào)用其方法blitme():
game_functions.py
def update_screen(ai_settings, screen, ship, alien, bullets):
--snip--
# 在飛船和外星人后面重繪所有的子彈
for bullet in bullets:
bullet.draw_bullet()
ship.blitme()
alien.blitme()
# 讓最近繪制的屏幕可見(jiàn)
pygame.display.flip()
我們先繪制飛船和子彈,再繪制外星人,讓外星人在屏幕上位于最前面。圖13-2顯示了屏幕 上的第一個(gè)外星人。
第一個(gè)外星人正確地現(xiàn)身后,下面來(lái)編寫(xiě)繪制一群外星人的代碼。
13.3 創(chuàng)建一群外星人
要繪制一群外星人,需要確定一行能容納多少個(gè)外星人以及要繪制多少行外星人。我們將首 先計(jì)算外星人之間的水平間距,并創(chuàng)建一行外星人,再確定可用的垂直空間,并創(chuàng)建整群外星人。
13.3.1 確定一行可容納多少個(gè)外星人
為確定一行可容納多少個(gè)外星人,我們來(lái)看看可用的水平空間有多大。屏幕寬度存儲(chǔ)在 ai_settings.screen_width中,但需要在屏幕兩邊都留下一定的邊距,把它設(shè)置為外星人的寬度。 由于有兩個(gè)邊距,因此可用于放置外星人的水平空間為屏幕寬度減去外星人寬度的兩倍:
available_space_x = ai_settings.screen_width – (2 * alien_width)
我們還需要在外星人之間留出一定的空間,即外星人寬度。因此,顯示一個(gè)外星人所需的水 平空間為外星人寬度的兩倍:一個(gè)寬度用于放置外星人,另一個(gè)寬度為外星人右邊的空白區(qū)域。 為確定一行可容納多少個(gè)外星人,我們將可用空間除以外星人寬度的兩倍:
number_aliens_x = available_space_x / (2 * alien_width)
我們將在創(chuàng)建外星人群時(shí)使用這些公式。
注意
令人欣慰的是,在程序中執(zhí)行計(jì)算時(shí),一開(kāi)始你無(wú)需確定公式是正確的,而可以嘗試直 接運(yùn)行程序,看看結(jié)果是否符合預(yù)期。即便是在最糟糕的情況下,也只是屏幕上顯示的 外星人太多或太少。你可以根據(jù)在屏幕上看到的情況調(diào)整計(jì)算公式。
13.3.2 創(chuàng)建多行外星人
為創(chuàng)建一行外星人,首先在alien_invasion.py中創(chuàng)建一個(gè)名為aliens的空編組,用于存儲(chǔ)全部 外星人,再調(diào)用game_functions.py中創(chuàng)建外星人群的函數(shù):
alien_invasion.py
import pygame
from pygame.sprite import Group
from settings import Settings
from ship import Ship
import game_functions as gf
def run_game():
--snip--
# 創(chuàng)建一艘飛船、一個(gè)子彈編組和一個(gè)外星人編組
ship = Ship(ai_settings, screen)
bullets = Group()
1 aliens = Group()
# 創(chuàng)建外星人群
2 gf.create_fleet(ai_settings, screen, aliens)
# 開(kāi)始游戲主循環(huán)
while True:
--snip—
3 gf.update_screen(ai_settings, screen, ship, aliens, bullets)
run_game()
由于我們不再在alien_invasion.py中直接創(chuàng)建外星人,因此無(wú)需在這個(gè)文件中導(dǎo)入Alien類(lèi)。 1處創(chuàng)建了一個(gè)空編組,用于存儲(chǔ)所有的外星人。接下來(lái),調(diào)用稍后將編寫(xiě)的函數(shù) create_fleet()(見(jiàn)2),并將ai_settings、對(duì)象screen和空編組aliens傳遞給它。然后,修改對(duì) update_screen()的調(diào)用,讓它能夠訪問(wèn)外星人編組(見(jiàn)3)。 我們還需要修改update_screen():
game_functions.py
def update_screen(ai_settings, screen, ship, aliens, bullets):
--snip--
ship.blitme()
aliens.draw(screen)
# 讓最近繪制的屏幕可見(jiàn)
pygame.display.flip()
對(duì)編組調(diào)用draw()時(shí),Pygame自動(dòng)繪制編組的每個(gè)元素,繪制位置由元素的屬性rect決定。 在這里,aliens.draw(screen)在屏幕上繪制編組中的每個(gè)外星人。
13.3.3 創(chuàng)建外星人群
現(xiàn)在可以創(chuàng)建外星人群了。下面是新函數(shù)create_fleet(),我們將它放在game_functions. py的末尾。我們還需要導(dǎo)入Alien類(lèi),因此務(wù)必在文件game_functions.py開(kāi)頭添加相應(yīng)的import 語(yǔ)句:
game_functions.py
--snip--
from bullet import Bullet
from alien import Alien
--snip--
def create_fleet(ai_settings, screen, aliens):
"""創(chuàng)建外星人群"""
# 創(chuàng)建一個(gè)外星人,并計(jì)算一行可容納多少個(gè)外星人
# 外星人間距為外星人寬度
1 alien = Alien(ai_settings, screen)
2 alien_width = alien.rect.width
3 available_space_x = ai_settings.screen_width - 2 * alien_width
4 number_aliens_x = int(available_space_x / (2 * alien_width))
# 創(chuàng)建第一行外星人
5 for alien_number in range(number_aliens_x):
# 創(chuàng)建一個(gè)外星人并將其加入當(dāng)前行
6 alien = Alien(ai_settings, screen)
alien.x = alien_width + 2 * alien_width * alien_number
alien.rect.x = alien.x
aliens.add(alien)
這些代碼大都在前面詳細(xì)介紹過(guò)。為放置外星人,我們需要知道外星人的寬度和高度,因此 在執(zhí)行計(jì)算前,我們先創(chuàng)建一個(gè)外星人(見(jiàn)1)。這個(gè)外星人不是外星人群的成員,因此沒(méi)有將 它加入到編組aliens中。在2處,我們從外星人的rect屬性中獲取外星人寬度,并將這個(gè)值存儲(chǔ) 到alien_width中,以免反復(fù)訪問(wèn)屬性rect。在3處,我們計(jì)算可用于放置外星人的水平空間,以 及其中可容納多少個(gè)外星人。
相比于前面介紹的工作,這里唯一的不同是使用了int()來(lái)確保計(jì)算得到的外星人數(shù)量為整 數(shù)(見(jiàn)4),因?yàn)槲覀儾幌M硞€(gè)外星人只顯示一部分,而且函數(shù)range()也需要一個(gè)整數(shù)。函數(shù) int()將小數(shù)部分丟棄,相當(dāng)于向下圓整(這大有裨益,因?yàn)槲覀儗幵该啃卸级喑鲆稽c(diǎn)點(diǎn)空間, 也不希望每行的外星人之間過(guò)于擁擠)。
接下來(lái),我們編寫(xiě)了一個(gè)循環(huán),它從零數(shù)到要?jiǎng)?chuàng)建的外星人數(shù)(見(jiàn)5)。在這個(gè)循環(huán)的主體 中,我們創(chuàng)建一個(gè)新的外星人,并通過(guò)設(shè)置x坐標(biāo)將其加入當(dāng)前行(見(jiàn)6)。將每個(gè)外星人都往右 推一個(gè)外星人的寬度。接下來(lái),我們將外星人寬度乘以2,得到每個(gè)外星人占據(jù)的空間(其中包 括其右邊的空白區(qū)域),再據(jù)此計(jì)算當(dāng)前外星人在當(dāng)前行的位置。最后,我們將每個(gè)新創(chuàng)建的外 星人都添加到編組aliens中。 如果你現(xiàn)在運(yùn)行這個(gè)游戲,將看到第一行外星人,如圖13-3所示。
這行外星人在屏幕上稍微偏向了左邊,這實(shí)際上是有好處的,因?yàn)槲覀儗⒆屚庑侨巳和乙疲?觸及屏幕邊緣后稍微往下移,然后往左移,以此類(lèi)推。就像經(jīng)典游戲《太空入侵者》,相比于只 往下移,這種移動(dòng)方式更有趣。我們將讓外形人群不斷這樣移動(dòng),直到所有外星人都被擊落或有 外星人撞上飛船或抵達(dá)屏幕底端。
注意
根據(jù)你選擇的屏幕寬度,在你的系統(tǒng)中,第一行外星人的位置可能稍有不同
關(guān)于“Python”的核心知識(shí)點(diǎn)整理大全12-CSDN博客文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-760360.html
關(guān)于“Python”的核心知識(shí)點(diǎn)整理大全25-CSDN博客文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-760360.html
往期快速傳送門(mén)??(在文章最后):
感謝大家的支持!歡迎訂閱收藏!專(zhuān)欄將持續(xù)更新!
到了這里,關(guān)于關(guān)于“Python”的核心知識(shí)點(diǎn)整理大全34的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!