Python專案實踐之二:外星人(1)

晴朗_不積跬步無以至千里發表於2021-01-03

Python專案實踐之二:外星人

在本文中,我們將在遊戲《外星人入侵》中新增外星人。首先,我們在螢幕上邊緣附近新增一個外星人,然後生成一群外星人。我們讓這群外星人向兩邊和下面移動,並刪除被子彈擊中的外星人。最後,我們將顯示玩家擁有的飛船數量,並在玩家的飛船用完後結束遊戲。

一、回顧專案

開發較大的專案時,進入每個開發階段前回顧一下開發計劃,搞清楚接下來要通過編寫程式碼來完成哪些任務都是不錯的主意。

1、alien_invasion.py

主檔案alien_invasion.py建立一系列整個遊戲都要用到的物件:
1、ai_settings:設定遊戲相關的內容(遊戲介面尺寸、飛船速度、子彈尺寸及速度等等)
2、screen:顯示遊戲相關的內容(遊戲介面、飛船、子彈等)
3、ship:例項化了一個飛船
4、bullets:例項化了一個子彈的編組
5、while迴圈:提供了一個遊戲執行的主迴圈,用於動態更新遊戲狀態

2、settings.py

檔案settings.py包含 Settings 類,這個類只包含方法 init() ,它初始化控制遊戲外觀和飛船速度的屬性。

3、game_functions.py

檔案game_functions.py包含一系列函式:
1、check_keydown_events:監聽鍵盤某個鍵按下時需要提供的操作
2、check_keyup_events:監聽鍵盤某個按下的鍵鬆開後需要提供的操作
3、check_events:監聽全部鍵盤和滑鼠的行為操作
4、update_screen:實時重繪遊戲介面
5、update_bullets:對子彈數量進行控制
6、fire_bullet:根據實際情況,建立併發射子彈

4、ship.py

檔案ship.py包含 Ship 類,這個類包含方法 init() 、管理飛船位置的方法 update() 以及在螢幕上繪製飛船的方法 blitme() 。

5、bullet.py

檔案bullet.py包含 Bullet 類,這個類包含方法 init() 、管理子彈位置的方法 update() 以及在螢幕上繪製飛船的方法 draw_bullet() 。

二、建立第一個外星人

建立一個外星人的方式與建立一個飛船的方式基本是一樣的,我們需要先找到一個外星人的圖片,圖片最好是無背景或者背景顏色與遊戲介面顏色一致的,這樣可以大大提升遊戲的美觀和體驗,把它放入到images資料夾中,如下圖就是一個背景顏色與遊戲介面一致的圖片:
在這裡插入圖片描述

1、建立 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.png')
        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)

解釋:Alien類與Ship類基本設定都是一樣的,只是位置設定不同而已,需要注意的是Alien類繼承了Sprite(精靈,不是雪碧哦),和子彈一樣,外星人也是多個不是一個,而Ship 只有一個。

2、建立Alien例項

在alien_invasion.py中例項化Alien:

1、在主迴圈外例項化Alien:

    #建立一個外星人
    alien = Alien(ai_settings, screen)

2、在主迴圈內顯示外星人:

        #每次迴圈重繪螢幕
        gf.update_screen(ai_settings, screen, ship, alien, bullets)

3、讓外星人出現在螢幕上

為讓外星人出現在螢幕上,我們在 game_functions.py的update_screen() 中呼叫其方法 blitme() :

def update_screen(ai_settings, screen, ship, alien, bullets):
    """更新螢幕上的影像,並切換到新螢幕"""
    # 每次迴圈時都重繪螢幕
    screen.fill(ai_settings.bg_color)

    # 在飛船和外星人後面重繪所有子彈 
    for bullet in bullets.sprites():
        bullet.draw_bullet()
    ship.blitme()
    alien.blitme()
    # 讓最近繪製的螢幕可見
    pygame.display.flip()

三、建立一群外星人

要繪製一群外星人,需要確定一行能容納多少個外星人以及要繪製多少行外星人。我們將首先計算外星人之間的水平間距,並建立一行外星人,再確定可用的垂直空間,並建立整群外星人。

確定一行可容納多少個外星人:

容納外星人寬度 = 遊戲介面寬度 - 2倍的外星人寬度(兩邊遊戲介面的空出來的寬度)

available_space_x = ai_settings.screen_width – (2 * alien_width)

容納外星人的個數 = 容納外星人的寬度 / 2倍的外星人寬度(一個寬度用於放置外星人,另一個寬度為外星人右邊的空白區域)

number_aliens_x = available_space_x / (2 * alien_width)
建立多行外星人:

為建立一行外星人,首先在alien_invasion.py中建立一個名為 aliens 的空編組(類似於建立子彈的編組),用於儲存全部外星人,再呼叫game_functions.py中建立外星人群的函式:
alien_invasion.py的run_game()函式中,主迴圈while之外新增:

	#建立一個外星人編組
	aliens = Group()
	#建立一個外星人
    # alien = Alien(ai_settings, screen) #替換為建立外星人群
    # 建立外星人群
    gf.create_fleet(ai_settings, screen, aliens)

game_functions.py中用於更新遊戲影像的update_screen()函式:

def update_screen(ai_settings, screen, ship, aliens, bullets):
    """更新螢幕上的影像,並切換到新螢幕"""
    # 每次迴圈時都重繪螢幕
    screen.fill(ai_settings.bg_color)

    # 在飛船和外星人後面重繪所有子彈 
    for bullet in bullets.sprites():
        bullet.draw_bullet()
    ship.blitme()
    aliens.draw(screen)
    # 讓最近繪製的螢幕可見
    pygame.display.flip()
建立外星人群:

主程式中呼叫了game_functions.py中的建立外星人群的新函式 create_fleet(),但是我們還未定義此,函式,現在來定義此函式:
game_functions.py中新增新函式 create_fleet():

def create_fleet(ai_settings, screen, aliens):
    """建立外星人群"""
    # 建立一個外星人,並計算一行可容納多少個外星人
    # 外星人間距為外星人寬度
    alien = Alien(ai_settings, screen)
    alien_width = alien.rect.width
    available_space_x = ai_settings.screen_width - 2 * alien_width
    number_aliens_x = int(available_space_x / (2 * alien_width))
    # 建立第一行外星人
    for alien_number in range(number_aliens_x):
        # 建立一個外星人並將其加入當前行
        alien = Alien(ai_settings, screen)
        alien.x = alien_width + 2 * alien_width * alien_number
        alien.rect.x = alien.x
        aliens.add(alien)

解釋:
1、首先,別忘記把Alien類匯入到game_functions.py中,要不然你再怎麼呼叫alien的屬性都會報錯。
2、計算遊戲介面每一行能放置幾個外星人,由於外星人的圖片素材是外部提供的,Alien類中並沒有它的長寬屬性,所以必須例項化一個外星人,通過rect對其確定大小,然後再計算個數。
3、通過for迴圈將允許建立的外星人的個數新增到外星人組中,當然,這裡要明確外星人組中每個外星人在遊戲介面的定位alien.x = alien_width + 2 * alien_width * alien_number(每個外星人都往右
推一個外星人的寬度)。

重構 create_fleet()

分析create_fleet()函式,我們發現函式內容結構複雜,而且不便於以後的使用,它在內部處理了一系列的問題而得到了很多結論性的結果,但是假設後面我們要使用它內部的結果,就不能直接呼叫了,這樣非常的不方便,因此,我們要對其進行重構,方便於後面的開發。

新增新函式 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

新增新函式 create_alien() :用於建立一個外星人,並設定其位置後放入外星人組

def create_alien(ai_settings, screen, aliens, alien_number):
    """建立一個外星人並將其放在當前行,新增到外星人組中"""
    alien = Alien(ai_settings, screen)
    alien_width = alien.rect.width
    alien.x = alien_width + 2 * alien_width * alien_number
    alien.rect.x = alien.x
    aliens.add(alien)

最後:重構 create_fleet()

def create_fleet(ai_settings, screen, aliens):
    """建立外星人群"""
    # 建立一個外星人,並計算一行可容納多少個外星人
    # 外星人間距為外星人寬度
    alien = Alien(ai_settings, screen)
    number_aliens_x = get_number_aliens_x(ai_settings, alien.rect.width)
    # 建立第一行外星人
    for alien_number in range(number_aliens_x):
        # 建立一個外星人並將其加入當前行
        create_alien(ai_settings, screen, aliens, alien_number)

這樣做就舒服了,以後要是別的程式還用到每行可容納多少個外星人,直接來這裡呼叫就可以了

新增行

目前,已經完成了新增一行外星人的目的,但是遊戲設定需要新增多行外星人。接下來,我們就來計算一下,遊戲介面能新增多少行外星人。

容納外星人的高度 = 遊戲介面高度 - 外星人高度(外星人與遊戲介面頂部的區域)- 最初外星人群與飛船的距離(外星人高度的兩倍)- 飛船的高度

available_space_y = ai_settings.screen_height – 3 * alien_height – ship_height

容納外星人的行數 = 容納外星人的高度 / 2倍外星人的高度(每個外星人間距1個外星人高度的距離)

number_rows = available_height_y / (2 * alien_height)

接下來,我們在game_functions.py新增新函式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

我們修改外星人的y座標,並在第一行外星人上方留出與外星人等高的空白區域。相鄰外星人行的y座標相差外星人高度的兩倍,因此我們將外星人高度乘以2,再乘以行號。第一行的行號為0,因此第一行的垂直位置不變,而其他行都沿螢幕依次向下放置。
修改game_functions.py中的create_alien(),將建立:

def create_alien(ai_settings, screen, aliens, row_number, alien_number):
    """建立一個外星人並將其放在當前行,新增到外星人組中"""
    alien = Alien(ai_settings, screen)
    alien_width = alien.rect.width
    alien.x = alien_width + 2 * alien_width * alien_number
    alien.rect.x = alien.x
    alien.rect.y = alien.rect.height + 2 * alien.rect.height * row_number
    aliens.add(alien)

好了,現在再把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, row_number, alien_number)

解釋:
1、number_aliens_x:每行最多可以放多少個外星人
2、number_rows:遊戲介面一共可以放多少行外星人
3、通過雙層for迴圈實現外星人群體佈局

最後,修改alien_invasion.py主程式中“# 建立外星人群”的程式碼(需要新增一個ship引數,因為計算行數的時候用到了飛船的高度):

gf.create_fleet(ai_settings, screen, ship, aliens)

四、移動外星人群

需求:外星人撞到螢幕邊緣後下移一定的距離,再沿相反的方向移動。

1、向右移動外星人

首先,在settings.py中的__init__方法中新增一個控制外星人速度的設定,繫結到物件本身:

		# 外星人設定
        self.alien_speed_factor = 1

然後,使用這個設定來建立 alien.py 中的 update()方法,表示向右移動外星人 :

    def update(self):
        """向右移動外星人"""
        self.x += self.ai_settings.alien_speed_factor
        self.rect.x = self.x

接下來,在game_functions.py末尾新增新函式 update_aliens(),表示更新外星人的位置 :

def update_aliens(aliens):
    """更新外星人群中所有外星人的位置"""
    aliens.update()

最後,在主程式的主迴圈中新增game_functions.py的呼叫即可:

		#呼叫外星人群移動顯示的函式
        gf.update_aliens(aliens)

2、建立表示外星人移動方向的設定

目前,已經實現外星人群整體向右移動,直至全部移出遊戲介面,接下來,我們需要實現外星人群移動到遊戲介面邊界後向下移動,然後再反向移動的功能。

在settings.py中的外星人設定新增向下移動的速度屬性和移動方向的判斷標準:

# 外星人設定
        self.alien_speed_factor = 1
        self.fleet_drop_speed = 10  #表示向下移動的速度
        # fleet_direction為1表示向右移,為-1表示向左移
        self.fleet_direction = 1

3、檢查外星人是否撞到了螢幕邊緣

現在需要編寫一個方法來檢查是否有外星人撞到了螢幕邊緣,還需修改 alien.py 中的 update() ,以讓每個外星人都沿正確的方向移動。

首先,在alien.py中新增一個判斷外星人是否撞到了螢幕邊緣的函式check_edges():

    def check_edges(self):
        """如果外星人位於螢幕邊緣,就返回True"""
        screen_rect = self.screen.get_rect()
        if self.rect.right >= screen_rect.right:
            return True
        elif self.rect.left <= 0:
            return True

其次,修改修改 alien.py 中的 update() :

    def update(self):
        """向左或向右移動外星人"""
        self.x += (self.ai_settings.alien_speed_factor * self.ai_settings.fleet_direction)
        self.rect.x = self.x

解釋:self.x(當前外星人的位置) = self.x + self.ai_settings.alien_speed_factor(移動速度)* self.ai_settings.fleet_directio(移動方向)

4、向下移動外星人群並改變移動方向

有外星人到達螢幕邊緣時,需要將整群外星人下移,並改變它們的移動方向。下面我們就對game_functions.py做修改,因為我們要在這裡檢查是否有外星人到達了左邊緣或右邊緣,game_functions.py是為遊戲提供邏輯處理的函式庫。

首先,要對外星人碰撞到螢幕邊界實現轉向向下的功能,所以在game_functions.py中新增一個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中新增一個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

最後,就是要修改game_functions.py中用於更新外星人群位置的update_aliens()函式,使外星人群能正確的顯示自己在螢幕的位置:

def update_aliens(ai_settings, aliens):
    """檢查是否有外星人位於螢幕邊緣,並更新整群外星人的位置"""
    check_fleet_edges(ai_settings, aliens)
    aliens.update()

我們修改了函式 update_aliens() ,在其中通過呼叫 check_fleet_edges() 來確定是否有外星人位於螢幕邊緣。現在,函式 update_aliens() 包含形參 ai_settings ,因此我們在主程式alien_invasion.py呼叫它時也要指定與ai_settings 對應的實參:

		#呼叫外星人群的函式
        # gf.update_aliens(aliens)
        gf.update_aliens(ai_settings, aliens)

如果你現在執行這個遊戲,外星人群將在螢幕上來回移動,並在抵達螢幕邊緣後向下移動。現在可以開始射殺外星人,檢查是否有外星人撞到飛船,或抵達了螢幕底端。

這是一篇讀書筆記,如有不妥之處,請各位指正!!!

相關文章