
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)中...