Alien invasion外星人入侵[Pygame下]

1676468755920.jpg

Alien invasion外星人入侵

接上文繼續(xù)開(kāi)發(fā)記分內(nèi)容,完整項(xiàng)目,調(diào)整界面。

Alien invasion外星人入侵[Pygame上] http://www.itdecent.cn/p/b5e061e45819

武裝飛船

開(kāi)發(fā)大型項(xiàng)目時(shí),做好規(guī)劃后再動(dòng)手編寫(xiě)項(xiàng)目很重要。規(guī)劃可確保你不偏離軌道,從而提高項(xiàng)目成功的可能性。

開(kāi)發(fā)出來(lái)的效果

在游戲《外星人入侵》中,玩家控制著一艘最初出現(xiàn)在屏幕底部中央的飛船。玩家可以使用箭頭鍵左右移動(dòng)飛船,還可以使用空格鍵進(jìn)行射擊。

游戲開(kāi)始時(shí),一群外星人出現(xiàn)在天空中,他們?cè)谄聊恢邢蛳乱苿?dòng)。玩家的任務(wù)是射殺這些外星人。

記分

按鍵play按鈕 用于啟動(dòng)游戲

玩家等級(jí)提高時(shí),增加游戲節(jié)奏

實(shí)現(xiàn)記分系統(tǒng)

添加Play按鈕

class GameStats():
    """跟蹤游戲的統(tǒng)計(jì)信息"""

    def __init__(self, ai_settings):
        """初始化統(tǒng)計(jì)信息"""
        self.ships_left = None
        self.ai_settings = ai_settings
        self.reset_stats()

        # 游戲啟動(dòng)處于非活動(dòng)狀態(tài)
        self.game_active = False
創(chuàng)建Button類

pygame沒(méi)有內(nèi)置創(chuàng)建按鈕的方法,需要我們創(chuàng)建

button.py

import pygame.font


class Button():

    def __init__(self, ai_settings, screen, msg):
        """初始化按鈕的屬性"""
        self.screen = screen
        self.screen_rect = screen.get_rect()

        # 設(shè)置按鈕的尺寸和其他屬性
        self.width, self.height = 200, 50
        self.button_color = (0, 255, 0)
        self.text_color = (255, 255, 255)
        self.font = pygame.font.SysFont(None, 48)

        # 創(chuàng)建按鈕的rect對(duì)象, 使其居中
        self.rect = pygame.Rect(0, 0, self.width, self.height)
        self.rect.center = self.screen_rect.center

        # 按鈕的標(biāo)簽只需要?jiǎng)?chuàng)建一次
        self.prep_msg(msg)

    def prep_msg(self, msg):
        """"將msg渲染為圖像, 并使其在按鈕上居中"""
        self.msg_image = self.font.render(msg, True, self.text_color, self.button_color)
        self.msg_image_rect = self.msg_image.get_rect()
        self.msg_image_rect.center = self.rect.center

    def draw_button(self):
        """繪制一個(gè)顏色填充的按鈕, 再繪制文本"""
        self.screen.fill(self.button_color, self.rect)
        self.screen.blit(self.msg_image, self.msg_image_rect)

pygame.font.SysFont 字體渲染,None使用默認(rèn)字體

font.render 將存儲(chǔ)在msg中的文本轉(zhuǎn)換為圖像,將圖像儲(chǔ)存在msg_image中

在屏幕上繪制按鈕

anlien_invasion.py

def run_game():
    # 初始化游戲并創(chuàng)建一個(gè)屏幕對(duì)象
    pygame.init()
     
    # 創(chuàng)建Play按鈕
    play_button = Button(ai_settings, screen, "Play")

     ....

    # 創(chuàng)建一個(gè)用于儲(chǔ)存游戲統(tǒng)計(jì)信息的實(shí)例
    stats = GameStats(ai_settings)

    # 開(kāi)始游戲的主循環(huán)
    while True:
        # 監(jiān)視鍵盤和鼠標(biāo)事件
      

        gf.update_screen(ai_settings, stats, screen, ship, aliens, bullets, play_button)


run_game()

game_funciton.py

def update_screen(ai_settings, stats, screen, ship, aliens, bullets, play_button):
 
    
    # 如果游戲處于非活動(dòng)狀態(tài),就繪制Play按鈕
    if not stats.game_active:
        play_button.draw_button()

    # 讓最近繪制的屏幕可見(jiàn)
    pygame.display.flip()
開(kāi)始游戲

玩家單擊Play按鈕時(shí),開(kāi)始新游戲,監(jiān)視與這個(gè)按鈕相關(guān)的鼠標(biāo)事件

監(jiān)聽(tīng)鼠標(biāo)事件

game_functions.py

def check_event(ai_settings, screen, stats, play_button, ship, bullets):
    """響應(yīng)按鍵和鼠標(biāo)事件"""
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            sys.exit()
        elif event.type == pygame.MOUSEBUTTONDOWN:
            # 鼠標(biāo)事件
            mouse_x, mouse_y = pygame.mouse.get_pos()
            check_play_button(stats, play_button, mouse_x, mouse_y)
重置游戲

避免play重復(fù)觸發(fā)

def check_play_button(ai_settings, screen, stats, play_button, ship, bullets, aliens, mouse_x, mouse_y):
    """玩家單機(jī)play按鈕時(shí)開(kāi)始游戲"""
    button_click = play_button.rect.collidepoint(mouse_x, mouse_y)
    if button_click and not stats.game_active:

        # 重置游戲統(tǒng)計(jì)信息
        stats.reset_stats()
        stats.game_active = True
def check_play_button(ai_settings, screen, stats, play_button, ship, bullets, aliens, mouse_x, mouse_y):
    """玩家單機(jī)play按鈕時(shí)開(kāi)始游戲"""
    button_click = play_button.rect.collidepoint(mouse_x, mouse_y)
    if button_click and not stats.game_active:

        # 重置游戲統(tǒng)計(jì)信息
        stats.reset_stats()
        stats.game_active = True

        # 清空外星人 子彈
        aliens.empty()
        bullets.empty()

        # 創(chuàng)建一群新的外星人 飛船居中
        create_fleet(ai_settings, screen, ship, aliens)
        ship.center_ship()
將Play按鈕切換到非活動(dòng)狀態(tài)

讓游戲僅在game_active為Fasle時(shí)才開(kāi)始

game_function.py

def check_play_button(ai_settings, screen, stats, play_button, ship, bullets, aliens, mouse_x, mouse_y):
    """玩家單機(jī)play按鈕時(shí)開(kāi)始游戲"""
    button_click = play_button.rect.collidepoint(mouse_x, mouse_y)
    if button_click and not stats.game_active:

        # 重置游戲統(tǒng)計(jì)信息
        ...

當(dāng)玩家點(diǎn)擊了Play按鈕且游戲當(dāng)前處于非活動(dòng)狀態(tài)時(shí),游戲才重新開(kāi)始

隱藏光標(biāo)

游戲開(kāi)始之后變隱藏起來(lái)

隱藏光標(biāo)

def check_play_button(ai_settings, screen, stats, play_button, ship, bullets, aliens, mouse_x, mouse_y):
    """玩家單機(jī)play按鈕時(shí)開(kāi)始游戲"""
    button_click = play_button.rect.collidepoint(mouse_x, mouse_y)
    if button_click and not stats.game_active:

        # 隱藏光標(biāo)
        pygame.mouse.set_visible(False)

游戲結(jié)束飛船被擊中 時(shí) 顯示光標(biāo)

顯示光標(biāo)

def ship_hit(ai_settings, stats, screen, ship, aliens, bullets):
    """響應(yīng)被外星人撞到的飛船"""
    if stats.ships_left > 0:
        # 將ships_left減1
        ....
    else:
        # game over
        stats.game_active = False
        # 顯示光標(biāo)
        pygame.mouse.set_visible(True)

提交等級(jí)

當(dāng)前將整群外星人都消滅干凈后,玩家將提高一個(gè)等級(jí),即加快游戲的節(jié)奏,讓游戲更難

修改速度與重置速度

有個(gè)初始化速度,速度增快的節(jié)奏

提高速度,與初始化速度

class Settings():
    """儲(chǔ)存《外星人入侵》的所有設(shè)置類"""

    def __init__(self):
        """初始化游戲的設(shè)置"""
        # 屏幕設(shè)置
        .....

        # 以什么樣的速度加快游戲節(jié)奏
        self.speedup_scale = 1.1

        self.initialize_dynamic_settings()

    def initialize_dynamic_settings(self):
        """初始化游戲設(shè)置"""
        self.ship_speed_factor = 1.5
        self.bullet_speed_factor = 3
        self.alien_speed_factor = 1

        # fleet_direction 為1表示向右移 -1表示向左移動(dòng)
        self.fleet_direction = 1

    def increase_speed(self):
        """提高速度設(shè)置"""
        self.ship_speed_factor *= self.speedup_scale
        self.bullet_speed_factor *= self.speedup_scale
        self.alien_speed_factor *= self.speedup_scale

game_function.py

點(diǎn)擊Play時(shí)

def start_game(ai_settings, screen, stats, ship, bullets, aliens):
    """ 開(kāi)始游戲 """

    # 重置游戲設(shè)置
    ai_settings.initialize_dynamic_settings()

外星人被清空時(shí)

def check_bulled_alien_collisions(ai_settings, screen, ship, bullets, aliens):
    # 檢查是否有子彈擊中外星人 如果是這樣的 刪除相應(yīng)的子彈和外星人
    collisions = pygame.sprite.groupcollide(bullets, aliens, True, True)

    if len(aliens) == 0:
        # 刪除現(xiàn)有的子彈并新建一群外星人
        bullets.empty()
        # 提速
        ai_settings.increase_speed()
        create_fleet(ai_settings, screen, ship, aliens)

射擊移動(dòng)靶心也是如此

記分

搞一個(gè)記分系統(tǒng),實(shí)時(shí)跟蹤玩家的得分,并顯示最高得分,當(dāng)前等級(jí)和余下飛船數(shù)

新建game_stats.py

顯示得分

新建scoreboard.py 文件 用戶記錄得分相關(guān)數(shù)據(jù)

import pygame.font


class Scoreboard:
    """顯示得分信息的類"""

    def __init__(self, ai_settings, screen, stats):
        """初始化顯示得分涉及的屬性"""
        self.score_image = None
        self.score_rect = None
        self.screen = screen
        self.screen_rect = screen.get_rect()
        self.ai_setting = ai_settings
        self.stats = stats

        # 顯示得分信息時(shí)使用的字體設(shè)置
        self.text_color = (30, 30, 30)
        self.font = pygame.font.SysFont(None, 48)

        # 準(zhǔn)備初始得分圖像
        self.prep_score()

    def prep_score(self):
        """將得分轉(zhuǎn)換一幅渲染的圖像"""
        score_str = str(self.stats.score)
        self.score_image = self.font.render(score_str, True, self.text_color, self.ai_setting.bg_color)

        # 將得分放在屏幕右上角
        self.score_rect = self.score_image.get_rect()
        self.score_rect.right = self.screen_rect.right - 20
        self.score_rect.top = self.screen_rect.top - 20


    def show_score(self):
        """在屏幕上顯示得分"""
        self.screen.blit(self.score_image, self.score_rect)

prep_score 將顯示的文本轉(zhuǎn)換為圖像

創(chuàng)建記分牌

需要在alien_invasion.py 中創(chuàng)建一個(gè)Scoreboard實(shí)例:

from scoreboard import Scoreboard

def run_game():
    ....
 # 創(chuàng)建一個(gè)用于儲(chǔ)存游戲統(tǒng)計(jì)信息的實(shí)例
    stats = GameStats(ai_settings)
    sb = Scoreboard(ai_settings, screen, stats)
    
    # 開(kāi)始游戲的主循環(huán)
    while True:

        gf.update_screen(ai_settings, stats, sb, screen, ship, aliens, bullets, play_button)

game_functions.py

def update_screen(ai_settings, stats, sb, screen, ship, aliens, bullets, play_button):


    # 顯示得分
    sb.show_score()

在外星人被消滅時(shí)更新積分

每次增加50,發(fā)生子彈與外星人碰撞時(shí)更新分組,修改傳遞參數(shù)

class Settings():
    """儲(chǔ)存《外星人入侵》的所有設(shè)置類"""

    def __init__(self):

        # 記分
        self.alien_points = 50

game_functions.py

def check_bulled_alien_collisions(ai_settings, stats, sb, screen, ship, bullets, aliens):
    # 檢查是否有子彈擊中外星人 如果是這樣的 刪除相應(yīng)的子彈和外星人
    collisions = pygame.sprite.groupcollide(bullets, aliens, True, True)

    if collisions:
        stats.score += ai_settings.alien_points
        sb.prep_score()
消滅的每個(gè)外星人都計(jì)入得分

目前一共子彈同時(shí)碰撞到多個(gè)外星人時(shí)是計(jì)算一次積分(增加字段寬度可以測(cè)試),或者兩顆子彈同事?lián)糁幸粋€(gè)外星人也會(huì)有如此的情形。

調(diào)整檢測(cè)子彈和外星人碰撞的方式

if collisions:
    for aliens in collisions.values():
        stats.score += ai_settings.alien_points * len(aliens)
        sb.prep_score()

如果字典collisions存在,我們就遍歷其中所有值。每個(gè)值都是一個(gè)列表,包含同一子彈擊中的所有外星人,

提高點(diǎn)數(shù)

玩家每提高一個(gè)等級(jí),游戲都變得更難,外星人的點(diǎn)數(shù)也提高。

settings.py

     def __init__(self):

        # 外星人點(diǎn)數(shù)提高速度
        self.score_scale = 1.5



    def increase_speed(self):
        """提高速度設(shè)置和外星人點(diǎn)數(shù)"""
        

        # 分?jǐn)?shù) * 點(diǎn)數(shù)
        self.alien_points = int(self.alien_points * self.score_scale)
        print("alien points " + str(self.alien_points))


將得分圓整

方便直接觀看,每三位用逗號(hào)隔開(kāi)

rounded_score = int(round(self.stats.score, -1))
score_str = "{:,}".format(rounded_score)

round() 通常精確小數(shù)點(diǎn)后多少位,如果是負(fù)數(shù)的化,則是10,100,1000等整數(shù)倍

最高得分

實(shí)現(xiàn)思路與得分相近,最高分來(lái)源是每次得分,而且不會(huì)被重置

game_stats.py

class GameStats:
    """跟蹤游戲的統(tǒng)計(jì)信息"""

    def __init__(self, ai_settings):
        """初始化統(tǒng)計(jì)信息"""
        
        # .....

        # 在任何情況下都不應(yīng)重制最高分
        self.high_score = 0

scoreboard.py

class Scoreboard:
    """顯示得分信息的類"""

    def __init__(self, ai_settings, screen, stats):
        """初始化顯示得分涉及的屬性"""
        
        # ....
          # 最高分和當(dāng)前得分
        self.prep_high_score()
        
     def prep_score(self):
        """將得分轉(zhuǎn)換一幅渲染的圖像"""
        rounded_score = int(round(self.stats.score, -1))
        score_str = "{:,}".format(rounded_score)
        
        
    def show_score(self):
        """在屏幕上顯示得分"""
        self.screen.blit(self.score_image, self.score_rect)
        self.screen.blit(self.high_score_image, self.high_score_rect)


    def prep_high_score(self):
        """將最高得分轉(zhuǎn)換為渲染等圖像"""
        high_score = int(round(self.stats.high_score, -1))
        high_score_str = "{:,}".format(high_score)
        self.high_score_image = self.font.render(high_score_str, True, self.text_color, self.ai_setting.bg_color)

        """將最高得分放在屏幕頂部中央"""
        self.high_score_rect = self.high_score_image.get_rect()
        self.high_score_rect.right = self.screen_rect.centerx
        self.high_score_rect.top = self.screen_rect.top

        

game_functions.py 調(diào)用入口


def check_bulled_alien_collisions(ai_settings, stats, sb, screen, ship, bullets, aliens):
    # 檢查是否有子彈擊中外星人 如果是這樣的 刪除相應(yīng)的子彈和外星人
    collisions = pygame.sprite.groupcollide(bullets, aliens, True, True)

    if collisions:
        for aliens in collisions.values():
            stats.score += ai_settings.alien_points * len(aliens)
            sb.prep_score()
        check_high_score(stats, sb)



def check_high_score(stats, sb):
    """檢查是否誕生了新的最高分"""
    if stats.score > stats.high_score:
        stats.high_score = stats.score
        sb.prep_high_score()

外星人被擊中時(shí),便去調(diào)用check_high_score去檢查是否誕生了新的最高分

最高分出現(xiàn)在中央,當(dāng)前分出現(xiàn)在右邊

顯示等級(jí)

首先在GameStats中添加當(dāng)前等級(jí)屬性,確保游戲開(kāi)始時(shí)都重置

與現(xiàn)實(shí)得分思路相近

  • 初始化等級(jí)1
  • 渲染圖像顯示在屏幕上 prep_level
  • 外星人都消滅完時(shí),增加一個(gè)等級(jí) check_bulled_alien_collisions
  • 游戲開(kāi)始play時(shí)重置等級(jí) start_game

GameStats.py

def reset_stats(self):
    """初始化在游戲運(yùn)行期間可能變化信息統(tǒng)計(jì)"""
    self.ships_left = self.ai_settings.ship_limit
    # 得分
    self.score = 0
    # 等級(jí)
    self.level = 0

Scoreboard.py


 def show_score(self):
        """在屏幕上顯示得分"""
        self.screen.blit(self.score_image, self.score_rect)
        self.screen.blit(self.high_score_image, self.high_score_rect)
        self.screen.blit(self.level_image, self.level_rect)

    def prep_level(self):
        """將等級(jí)轉(zhuǎn)換為渲染的圖像"""
        self.level_image = self.font.render(str(self.stats.level), True, self.text_color, self.ai_setting.bg_color)

        # 將等級(jí)放在得分下方
        self.level_rect = self.level_image.get_rect()
        self.level_rect.right = self.score_rect.right
        self.level_rect.top = self.score_rect.bottom + 10

game_functions.py

def start_game(ai_settings, screen, stats, sb, ship, bullets, aliens):
    """ 開(kāi)始游戲 """

   
    # 重新記分牌圖像
    sb.prep_score()
    sb.prep_high_score()
    sb.prep_level()

需要增加一個(gè)入?yún)b(scoreboard)

屏幕對(duì)應(yīng)的數(shù)字也可以去拼接參數(shù)顯示得分帶標(biāo)簽,如Score,Hight Score和Level

顯示剩余飛船數(shù)

ship.py

scoreboard.py

    def prep_ships(self):
        """顯示還剩余多少艘飛船"""
        self.ships = Group()
        for ship_number in range(self.stats.ships_left):
            ship = Ship(self.ai_settings, self.screen)
            ship.rect.x = 10 + ship_number * ship.rect.width
            ship.rect.y = 10
            self.ships.add(ship)
            
            
    def show_score(self):
        """在屏幕上顯示得分"""
        self.screen.blit(self.score_image, self.score_rect)
        self.screen.blit(self.high_score_image, self.high_score_rect)
        self.screen.blit(self.level_image, self.level_rect)

        # 繪制飛船
        self.ships.draw(self.screen)         

在game_functions.py中調(diào)用

飛船發(fā)生撞擊時(shí),更新記分牌

def ship_hit(ai_settings, stats, sb, screen, ship, aliens, bullets):
    """響應(yīng)被外星人撞到的飛船"""
    if stats.ships_left > 0:
        # 將ships_left減1
        stats.ships_left -= 1

        # 更新記分牌
        sb.prep_ships()

也需要把想對(duì)應(yīng)的參數(shù)sb添加上去


如今游戲部分已經(jīng)完成,雖然很期待的樣子,自然也少不了成長(zhǎng),跟著文本來(lái),也難免失去一下思考,新的2023也必在春天成長(zhǎng)!

2023/02/15 成都 孕育未來(lái)中...

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容