用python入侵別人手機,python小游戲----外星人入侵
用python入侵別人手機,python小游戲----外星人入侵
源代碼:
AlienInvasion/game at main · CrashBugger/AlienInvasion (github.com)
本文來自作者對《python編程-從入門到實踐》的學習記錄,剛剛入門python,小白一個,若有錯誤,歡迎大佬指出。
圖片資源:
用python入侵別人手機,
just nobibi,show me the code!話不多說,開始項目。
1.創建pygame窗口響應用戶輸出
導包
import pygame
import sys
import settings
接下來
開始進行初步準備sssssssss
def run_game():# 初始化游戲并創建一個屏幕對象pygame.init()screen = pygame.display.set_mode((1200, 800))pygame.display.set_caption("Alien Invasion")# 游戲主循環while True:# 監視鍵盤和鼠標時間for event in pygame.event.get():if event == pygame.QUIT:sys.exit()# 讓最近的繪制的屏幕可見pygame.display.flip()
- ?其中pygame.init()方法初始化背景設置
- pygame.display.set_mode()創建一個名為screen的窗口對象,以后我們將在這里面繪制圖形元素,需要傳入一個元組,表示窗口的長高。screen是一個surface對象
- while循環控制游戲進行,for循環偵聽事件,pygame.event.get()方法拿到事件列表,當檢測到用戶離開時,系統退出
-
display.flip()方法讓最近繪制的屏幕可見
2.設置背景色
python小游戲代碼大全、先上代碼
def run_game():# 初始化游戲并創建一個屏幕對象pygame.init()screen = pygame.display.set_mode((1200, 800))pygame.display.set_caption("Alien Invasion")# shezhibeijingsebg_color = (230, 230, 230)# 游戲主循環while True:# 監視鍵盤和鼠標時間for event in pygame.event.get():if event == pygame.QUIT:sys.exit()# 每次循環重新繪制屏幕screen.fill(bg_color)# 讓最近的繪制的屏幕可見pygame.display.flip()
- 創建一個元組bg_color存儲RGB顏色,接下來在主循環中在screen中填充顏色,
3.創建設置類
?這一步對前一步進行優化,創建一個settings類,用來保存我們的設置
class Settings():def __init__(self):self.screen_width = 1200self.screen_height = 800self.bg_color = (230, 230, 230)
接下來回到主方法創建這個類的實例進行設置
def run_game():# 初始化游戲,并創建一個屏幕對象pygame.init()ai_settings = settings.Settings()screen = pygame.display.set_mode((ai_settings.screen_width, ai_settings.screen_height))pygame.display.set_caption("Ailien Invasion")# bg_color = (230, 230, 230)while True:# 監聽事件for event in pygame.event.get():if event.type == pygame.QUIT:sys.exit()# 每次循環重置屏幕screen.fill(ai_settings.bg_color)# 最近繪制的屏幕可見pygame.display.flip()
4.創建ship類并繪制飛船
創建一個新的文件夾,命名為images,將ship.bmp放進去,接下來創建ship類
import pygameclass Ship():def __init__(self, screen):self.screen = screen# 加載飛船圖像并獲取外接矩形self.image = pygame.image.load("D:\PyCharm\Code\project\game\images\ship.bmp")self.rect = self.image.get_rect()self.screen_rect = screen.get_rect()# 將飛船放在屏幕底部中央self.rect.centerx = self.screen_rect.centerxself.rect.bottom = self.screen_rect.bottomdef blitme(self):"""在指定位置繪制飛船"""self.screen.blit(self.image, self.rect)
- pygame可以像處理矩形一樣處理游戲元素,處理rect對象,可以使用矩形中心xy坐標和矩形四角
- 要將飛船顯示在中央,需要設置rect對象的center,centerx或centery;如果要將飛船與邊緣對其,可以設置其top,bottom,left,right屬性;如果要調整坐標,需要設置其x,y屬性,注意原點在左上角。
- 在主方法中加入飛船
def run_game():# 初始化游戲,并創建一個屏幕對象pygame.init()ai_settings = settings.Settings()screen = pygame.display.set_mode((ai_settings.screen_width, ai_settings.screen_height))pygame.display.set_caption("Ailien Invasion")# 創建一艘飛船ship = Ship(screen)while True:# 監聽事件for event in pygame.event.get():if event.type == pygame.QUIT:sys.exit()# 每次循環重置屏幕screen.fill(ai_settings.bg_color)ship.blitme()# 最近繪制的屏幕可見pygame.display.flip()
?5.重構模塊geme_functions
- 我們將游戲中的各個控制方法抽離到一個專門的模塊
- game_functions.py
import sys
import pygame
import shipfrom game import settingsdef check_events():"""響應按鍵和鼠標事件"""for event in pygame.event.get():if event.type == pygame.QUIT:sys.exit()def update_screen(ai_settings: settings.Settings, screen, ship: ship.Ship):"""更新屏幕上的圖像,并切換到新屏幕"""# 每次循環chonghuipingmuscreen.fill(ai_settings.bg_color)ship.blitme()# 最近繪制的屏幕可見pygame.display.filp()
?這些都是原本主循環中的方法,現在整合到一個模塊
主方法在修改一下
pygame外星人入侵、先把剛創建的模塊導包
import game_functions as gf
def run_game():# 初始化游戲,并創建一個屏幕對象pygame.init()ai_settings = settings.Settings()screen = pygame.display.set_mode((ai_settings.screen_width, ai_settings.screen_height))pygame.display.set_caption("Ailien Invasion")# 創建一艘飛船ship = Ship(screen)while True:# 監聽事件gf.check_events()# 每次循環重置屏幕gf.update_screen(ai_settings, screen, ship)
6.駕駛飛船
先在ship類中新加一個屬性moving_right=False,當檢測到移動時,置位true,并新定義update方法,更新飛船位置
- Ship類
def __init__(self, screen):self.screen = screen# 加載飛船圖像并獲取外接矩形self.image = pygame.image.load("D:\PyCharm\Code\project\game\images\ship.bmp")self.rect = self.image.get_rect()self.screen_rect = screen.get_rect()# 將飛船放在屏幕底部中央self.rect.centerx = self.screen_rect.centerxself.rect.bottom = self.screen_rect.bottom# 移動標志self.moving_right = Falsedef blitme(self):"""在指定位置繪制飛船"""self.screen.blit(self.image, self.rect)def update(self):if self.moving_right:self.rect.centerx += 1
我們在game_functions.py的check_events方法中加入檢測用戶鍵盤的代碼
- game_functions.py
def check_events(ship: ship.Ship):"""響應按鍵和鼠標事件"""for event in pygame.event.get():if event.type == pygame.QUIT:sys.exit()# 用戶按下鍵盤elif event.type == pygame.KEYDOWN:if event.key == pygame.K_RIGHT:ship.moving_right = Trueelif event.type == pygame.KEYUP:if event.key == pygame.K_RIGHT:ship.moving_right = False
當用按下鍵盤時,我們在event檢測其type屬性,若為keydown,再進一步判斷是否為向右鍵,并將ship類中的moving——righ屬性置為true,當玩家抬起右鍵時,檢測到keyup,將其置為false,
并在主方法中不斷調用ship類的update方法
- 主方法
def run_game():# 初始化游戲,并創建一個屏幕對象pygame.init()ai_settings = settings.Settings()screen = pygame.display.set_mode((ai_settings.screen_width, ai_settings.screen_height))pygame.display.set_caption("Ailien Invasion")# 創建一艘飛船ship = Ship(screen)while True:# 監聽事件gf.check_events(ship)# 更新ship.update()# 每次循環重置屏幕gf.update_screen(ai_settings, screen, ship)
7.調整飛船速度并限制飛船移動邊界
- 在settings類中新加屬性self.ship_speed_factor用于控制飛船速度
- 接下來在ship的方法init方法傳入settings對象,并在update方法中用他的屬性修改坐標,因為rect只存儲整數部分的值,所以為了精細控制速度,我們用float方法返回rect.centerx保存到center屬性,并在update方法對center修改,最后再用center覆蓋centerx。
- 判斷邊界只需要在update方法中判斷當前rect的left屬性和right屬性是否超出邊界。
Ship類
class Ship():def __init__(self, screen, ai_settings: Settings):self.screen = screen# 加載飛船圖像并獲取外接矩形self.image = pygame.image.load("D:\PyCharm\Code\project\game\images\ship.bmp")self.rect = self.image.get_rect()self.screen_rect = screen.get_rect()# 將飛船放在屏幕底部中央self.rect.centerx = self.screen_rect.centerxself.rect.bottom = self.screen_rect.bottom# 移動標志self.moving_right = Falseself.moving_left = False# 飛船設置self.ai_settings = ai_settings# 在飛船的center屬性中存儲小數值self.center = float(self.rect.centerx)def blitme(self):"""在指定位置繪制飛船"""self.screen.blit(self.image, self.rect)def update(self):# 加上邊界判斷if self.moving_right and self.rect.right < self.screen_rect.right:self.center += self.ai_settings.ship_speed_factorif self.moving_left and self.rect.left > 0:self.center -= self.ai_settings.ship_speed_factor# 覆蓋self.rect.centerx = self.center
8.重構check_functions
def check_keydown_events(event, ship):if event.key == pygame.K_RIGHT:ship.moving_right = Trueelif event.key == pygame.K_LEFT:ship.moving_left = Truedef check_keyup_events(event, ship):if event.key == pygame.K_RIGHT:ship.moving_right = Falseelif event.key == pygame.K_LEFT:ship.moving_left = Falsedef check_events(ship: ship.Ship):"""響應按鍵和鼠標事件"""for event in pygame.event.get():if event.type == pygame.QUIT:sys.exit()# 用戶按下鍵盤elif event.type == pygame.KEYDOWN:check_keydown_events(event, ship)elif event.type == pygame.KEYUP:check_keyup_events(event, ship)
- 提取出兩個方法,如圖
9.創建子彈類并加入編組
外星人入侵循環導入?bullet.py
import pygame
from pygame.sprite import Spritefrom game.settings import Settings
from game.ship import Shipclass Bullet(Sprite):def __init__(self, ai_settings: Settings, screen, ship: Ship):"""在飛船所在位置創建子彈"""super().__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_factordef update(self):"""向上移動子彈"""# 更新y坐標self.y -= self.speed_factor# 覆蓋self.rect.y = self.ydef draw_bullet(self):"""在屏幕上繪制子彈"""pygame.draw.rect(self.screen, self.color, self.rect)
- 我們繼承sprite類,可以將子彈編組,同時操作編組中的元素。并傳入settings對象ship對象和screen對象
- 用rect存儲子彈矩形,并設置其centerx和top屬性,讓它與飛船相同
- 跟上一個相同的原因,我們用float()精細調整子彈y坐標
我們在主方法導包并創建Group()實例,并將其傳入while循環中的三個方法
from pygame.sprite import Group
# 初始化游戲,并創建一個屏幕對象pygame.init()ai_settings = settings.Settings()screen = pygame.display.set_mode((ai_settings.screen_width, ai_settings.screen_height))pygame.display.set_caption("Ailien Invasion")# 創建一艘飛船ship = Ship(screen, ai_settings)# 創建用于存儲子彈的編組bullets = Group()while True:# 監聽事件gf.check_events(ship, bullets)# 更新ship.update()# 更新子彈位置bullets.update()# 每次循環重置屏幕gf.update_screen(ai_settings, screen, ship, bullets)
- 編組的作用就是存儲子彈,并且當調用update()方法時,自動對里面的每個子彈調用update方法,bullets.update()將被每顆子彈調用
10.Fire!開火
- 這里期望玩家按空格鍵可以完成開火
- 我們在functions對check_keydown方法加入對空格的判斷若判斷到,則在編組中新加入子彈;并在update_screen方法中重繪子彈,注意重繪子彈應在screen.flip()方法調用之前
- 注意修改方法的參數
class Bullet(Sprite):def __init__(self, ai_settings: Settings, screen, ship: Ship):"""在飛船所在位置創建子彈"""super().__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_factordef update(self):"""向上移動子彈"""# 更新y坐標self.y -= self.speed_factor# 覆蓋self.rect.y = self.ydef draw_bullet(self):"""在屏幕上繪制子彈"""pygame.draw.rect(self.screen, self.color, self.rect)
- 成功開火后,有個問題,那些飛出屏幕外的子彈,仍然留在內存中,這樣越積越多,會讓我們的游戲慢的龜爬一樣,所以在主方法while循環中添加一個刪除子彈的方法,判斷子彈的bottom屬性是否小于等于0,成立則從編組中刪除掉
while True:# 監聽事件gf.check_events(ai_settings, screen, ship, bullets)# 更新ship.update()# 更新子彈位置bullets.update()# 刪除已經消失的子彈for bullet in bullets.copy():if bullet.rect.bottom <= 0:bullets.remove(bullet)# 每次循環重置屏幕gf.update_screen(ai_settings, screen, ship, bullets)
- 下來我們在對代碼進行優化,創建update_bullets函數和fire_bullets來將原本開火和更新的代碼抽離
- games_functions.py
-
def update_bullets(bullets: Bullet):"""更新子彈未位置"""# 更新位置bullets.update()# 刪除已經消失的子彈for bullet in bullets.copy():if bullet.rect.bottom <= 0:bullets.remove(bullet)def fire_bullets(ai_settings: Settings, screen: surface, ship: ship.Ship, bullets: Bullet):# 若子彈數量小于3,創建一顆新子彈,if len(bullets) < ai_settings.bullets_allowed:new_bullet = Bullet(ai_settings, screen, ship)bullets.add(new_bullet)
修改其中的keydown函數
-
def check_keydown_events(event, ai_settings: Settings, screen, ship, bullets: Bullet):if event.key == pygame.K_RIGHT:ship.moving_right = Trueelif event.key == pygame.K_LEFT:ship.moving_left = Trueelif event.key == pygame.K_SPACE:fire_bullets(ai_settings, screen, ship, bullets)
11.創建外星人
-
我們首先改變一下游戲退出的方式,按下Q鍵即可退出,在game_functions.py中的key_down方法加上下面一條
-
elif event.key == pygame.K_q:sys.exit(1)
創建外星人類
import pygame
from pygame import surface
from pygame.sprite import Spritefrom game.settings import Settingsclass Alien(Sprite):"""表示單個外星人的類"""def __init__(self, ai_settings: Settings, screen: surface):# 初始化外星人并設置其起始位置super(Alien, self).__init__()self.screen = screenself.ai_settings = ai_settings# 加載外星人圖像,設置其rect屬性self.image = pygame.image.load(r"D:\PyCharm\Code\project\game\images\alien.bmp")self.rect = self.image.get_rect()# 每個外星人初始位置都在屏幕左上角附近self.rect.x = self.rect.widthself.rect.y = self.rect.height# 存儲外星人的準確位置self.x = float(self.rect.x)def blitme(self):"""在指定位置繪制外星人"""self.screen.blit(self.image, self.rect)
- 講解同ship類一樣,不在贅述
- 接下來我們要將外星人在圖像上畫出來,需要在主方法中創建一個實例
-
# 創建外星人實例alien = Alien(ai_settings, screen)
并在game_functions中修改update_screen方法
-
python武裝飛船在手機上運行,game_functions.py
def update_screen(ai_settings: Settings, screen, ship: ship.Ship, alien: Alien, bullets: Bullet):"""更新屏幕上的圖像,并切換到新屏幕"""# 每次循環重繪屏幕screen.fill(ai_settings.bg_color)ship.blitme()# 繪制外星人alien.blitme()# 重繪子彈for bullet in bullets.sprites():bullet.draw_bullet()# 最近繪制的屏幕可見pygame.display.flip()
- ?調用個blitme方法即可,注意還需要在flip方法調用之前
- 嘗試成功,接下來我們要創建一行外星人
- 在game_functions.py中加入如下方法
- 在主方法中循環之前加入
-
# 創建外星人群aliens = Group()gf.create_fleet(ai_settings, screen, aliens)
aliens是一個空的編組,前面介紹過,編組可以對其中的每個元素調用方法,并將它傳入create_fleet()方法,這個方法在game_functions.py中定義
-
game_functions.py
def create_fleet(ai_settings: Settings, screen, aliens: Group):"""創建外星人群"""# 創建一個外星人,并計算一行可以容納多少個外星人alien: Alien = Alien(ai_settings, screen)alien_width = alien.rect.widthavailable_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):newalien = Alien(ai_settings, screen)newalien.x = alien_width + 2 * alien_width * alien_numbernewalien.rect.x = newalien.xaliens.add(newalien)
- 首先計算一行可以容納多少個外星人,間距我們設置為外星人的寬度,接下來在編組中加入新建的外星人
12.重構creat_fleet()
def create_fleet(ai_settings: Settings, screen, aliens: Group):"""創建外星人群"""alien = Alien(ai_settings, screen)number_aliens_x = get_number_aliens(ai_settings, alien.rect.width, )for alien_number in range(number_aliens_x):create_alien(ai_settings, screen, aliens, alien_number)def get_number_aliens(ai_settings: Settings, alien_width: int) -> int:"""獲取一行容納的外星人數量"""available_space_x = ai_settings.screen_width - 2 * alien_width# 外星人間距為外星人寬度number_aliens_x = int(available_space_x / (2 * alien_width))return number_aliens_xdef create_alien(ai_settings, screen, aliens: Group, alien_number):"""創建一個外星人并放在當前行"""alien = Alien(ai_settings, screen)alien_width = alien.rect.widthalien.x = alien_width + 2 * alien_width * alien_numberalien.rect.x = alien.xaliens.add(alien)
將其中的幾個功能提取出來
13.添加多行外星人
game_functions.py
def get_number_rows(ai_settings: Settings, ship_height, alien_height) -> int:"""計算能容納多少行"""available_space_y = (ai_settings.screen_height - (3 * alien_height) - ship_height)number_rows = int(available_space_y / (2 * alien_height))return number_rows
- 加入上述代碼
def create_fleet(ai_settings: Settings, screen, ship: ship.Ship, aliens: Group):"""創建外星人群"""alien = Alien(ai_settings, screen)number_aliens_x = get_number_aliens(ai_settings, alien.rect.width)number_rows = get_number_rows(ai_settings, ship.rect.height, alien.rect.height)for alien_number in range(number_aliens_x):for alien_row in range(number_rows):create_alien(ai_settings, screen, aliens, alien_number, alien_row)
def create_alien(ai_settings, screen, aliens: Group, alien_number, row_number):"""創建一個外星人并放在當前行"""alien = Alien(ai_settings, screen)alien_width = alien.rect.width# 當前xalien.x = alien_width + 2 * alien_width * alien_number# 當前yalien.rect.y = alien.rect.height + 2 * alien.rect.height * row_numberalien.rect.x = alien.xaliens.add(alien)
- 修改create_fleet方法和create_alien方法
- create_alien中加入一個參數row_number,表示當前應該添加到第幾行,并據此修改y坐標
- create_fleet方法中for循環新加一層層數循環
14.外星人移動
首先在settings.py中添加設置參數
- settings.py
# 外星人設置self.alien_speed_factor = 0.5#外星人水平移動速度self.fleet_drop_speed = 10#外星人豎直移動速度self.fleet_direction = 1 #移動方向: 1為向右,-1向左
- ?Alien.py中加入下述代碼
def update(self):"""向左向右移動外星人"""self.x += self.ai_settings.alien_speed_factor * self.ai_settings.fleet_directionself.rect.x = self.xdef check_edges(self):"""如果外星人到達邊緣,返回True"""screen_rect = self.screen.get_rect()if self.rect.right >= screen_rect.right:return Trueelif self.rect.left <= 0:return True
- game_functions.py中加入
def change_fleet_direction(ai_settings, aliens):"""將外星人整體下移,并改變他們方向"""for alien in aliens.sprites():alien.rect.y += ai_settings.fleet_drop_speedai_settings.fleet_direction *= -1def check_fleet_edges(ai_settings: Settings, aliens):"""有外星人到達邊緣時采取相應的措施"""for alien in aliens.sprites():if alien.check_edges():change_fleet_direction(ai_settings, aliens)breakdef update_aliens(ai_settings, aliens):"""檢查是否有外星人位于屏幕邊緣,并更新調整外星人位置"""check_fleet_edges(ai_settings, aliens)aliens.update()
- update_aliens為我們對主方法提供的接口,上面兩個為輔助函數
- 主方法while中調用update_aliens方法
# 更新aliensgf.update_aliens(ai_settings, aliens)
15.射殺外星人并生成新的外星人群
有外星人入侵嗎,我們需要調用pygame.sprite.groupcollied方法,這個方法檢測兩個編組中的元素是否重合,重合的話進行處理,并返回一個字典,每個鍵值對為子彈-外星人。其中第一個True表示重合的話刪除第一個編組中的元素,第二個true表示刪除第二個編組中的元素。我們在更新子彈位置時調用這個方法,并增加主方法中的參數調用
- 擊殺外星人后,我們需要判斷是否需要生成新的外星人,若編組為空,重新調用生成外星人的方法
- game_functions.py
def update_bullets(ai_settings, screen, ship, aliens: Alien, bullets: Sprite):"""更新子彈未位置"""# 更新位置bullets.update()# 刪除已經消失的子彈for bullet in bullets.copy():if bullet.rect.bottom <= 0:bullets.remove(bullet)check_bullet_alien_collision(ai_settings, screen, ship, aliens, bullets)def check_bullet_alien_collision(ai_settings, screen, ship, aliens, bullets):# 檢查是否有子彈擊中外星人collisions = pygame.sprite.groupcollide(bullets, aliens, True, True)# 更新外星人if len(aliens) == 0:bullets.empty()create_fleet(ai_settings, screen, ship, aliens)
16.Boom!!!飛船與外星人相撞
如果飛船與外星人相撞或者外星人到底部,我們讓游戲重置,重新生成外星人,并將飛船居中
ship.py
def center_ship(self):"""讓飛船居中"""self.center = self.screen_rect.centerx
- 我們還需要將飛船的命數減一,為此我們新建一個GameStatus類,用于記錄游戲狀態信息
- 在Settings.py中新加屬性
-
self.ship_limit = 3
- GameStatus.py
class GameStatus():"""跟蹤游戲的統計信息"""def __init__(self, ai_settings):"""初始化統計的信息"""self.ai_settings = ai_settingsself.reset_status()def reset_status(self):"""初始化在游戲運行期間可能變化的信息"""self.ships_left = self.ai_settings.ship_limit
?game_functions.py
def update_aliens(ai_settings, stats, screen, ship, bullets, aliens):"""檢查是否有外星人位于屏幕邊緣,并更新調整外星人位置"""check_fleet_edges(ai_settings, aliens)aliens.update()# 檢測外星人和飛船是否相撞if pygame.sprite.spritecollideany(ship, aliens):ship_hit(ai_settings, stats, screen, ship, aliens, bullets)# 檢查外星人是否撞到底部check_aliens_bottom(aliens, ai_settings, stats, screen, ship, bullets)def ship_hit(ai_settings: Settings, status: GameStatus, screen, ship: ship.Ship, aliens, bullets):"""響應外星人撞到飛船"""# 將飛船數量ship_left減一status.ships_left -= 1# 清空外星人和子彈aliens.empty()bullets.empty()# 創建一群新的外星人,重置飛船create_fleet(ai_settings, screen, ship, aliens)ship.center_ship()# 暫停sleep(0.5)def check_aliens_bottom(aliens: Alien, ai_settings: Settings, stats: GameStatus,screen: Surface, ship: ship.Ship, bullets):"""檢查是否有外星人到達底部"""screen_rect = screen.get_rect()for alien in aliens:if alien.rect.bottom >= screen_rect.bottom:# 像飛船撞到飛船一樣處理ship_hit(ai_settings, stats, screen, ship, aliens, bullets)break
我們調用update_aliens方法時,順便檢查一下飛船與外星人是否相撞,通過
pygame.sprite.spritecollideany(ship, aliens)
Python外星人入侵,方法,第一個參數為一個飛船對象,第二個參數為一個編組,
17.游戲結束
game_functions.py的__ini__t中加入
# 游戲剛啟動處于活動狀態self.game_active = True
- 這個屬性讓我們可以再玩家命數耗盡后置為False退出游戲。
- 改動game_functions.py方法,加入判斷
def ship_hit(ai_settings: Settings, status: GameStatus, screen, ship: ship.Ship, aliens, bullets):"""響應外星人撞到飛船"""# 將飛船數量ship_left減一if status.ships_left > 0:status.ships_left -= 1# 清空外星人和子彈aliens.empty()bullets.empty()# 創建一群新的外星人,重置飛船create_fleet(ai_settings, screen, ship, aliens)ship.center_ship()# 暫停sleep(0.5)else:status.game_active = False
- 主方法的while循環改為
-
while True:# 監聽事件gf.check_events(ai_settings, screen, ship, bullets)if stats.game_active:# 更新ship.update()# 更新子彈gf.update_bullets(ai_settings, screen, ship, aliens, bullets)# 更新aliensgf.update_aliens(ai_settings, stats, screen, ship, bullets, aliens)# 每次循環重置屏幕gf.update_screen(ai_settings, screen, ship, aliens, bullets)
18.添加開始按鈕
- button.py
import pygame.font
class Button():def __init__(self, ai_settings: Settings, screen: Surface, msg):"""初始化按鈕的屬性"""self.screen = screenself.screen_rect = screen.get_rect()# 設置按鈕的尺寸和其他屬性self.width, self.height = 200, 50self.button_color = (0, 255, 0)self.text_color = (255, 255, 255)self.font = pygame.font.SysFont(None, 48)# 創建按鈕的rect對象,并使其居中self.rect = pygame.Rect(0, 0, self.width, self.height)self.rect.center = self.screen_rect.center# 按鈕標簽只需創建一次self.prep_msg(msg)
- font屬性中我們調用pygame.font()方法,None表示用默認字體,48指的是字體字號。為了讓按鈕在屏幕居中,我們創建一個rect對象,并讓他居中
- 接下來在新建一個方法prep_msg方法來處理按鈕的渲染和繪制按鈕的方法
def prep_msg(self, msg):"""將msg渲染為圖像,并將其在按鈕上居中"""self.msg_image = self.font.render(self, True, self.text_color, self.button_color)self.msg_image_rect = self.msg_image.get_rect()self.msg_image_rect.center = self.rect.centerdef draw_button(self):"""繪制一個用顏色填充的按鈕,在繪制文本"""self.screen.fill(self.button_color, self.rect)self.screen.blit(self.msg_image, self.msg_image_rect)
- 其中的font.render方法將存儲在msg中的文本轉換為圖像,并將其存儲在msg_image中,其中的True參數表示開啟抗鋸齒功能,可以讓文字邊緣更光滑。接下來最后調通過rect調整按鈕位置。
- 接下來draw_button來繪制按鈕。
- game_functions.py的update_screen中加入判斷游戲活動狀態的if語句,若不在活動狀態,繪制一個按鈕
-
def update_screen(ai_settings: Settings, screen, stats: GameStatus, ship: ship.Ship, aliens: Group, bullets: Bullet,play_button: Button):"""更新屏幕上的圖像,并切換到新屏幕"""# 每次循環重繪屏幕screen.fill(ai_settings.bg_color)ship.blitme()# 繪制外星人aliens.draw(screen)# 重繪子彈for bullet in bullets.sprites():bullet.draw_bullet()if not stats.game_active:play_button.draw_button()# 最近繪制的屏幕可見pygame.display.flip()
主方法中創建按鈕實例,并將其傳入update_screen方法中
-
# 創建play按鈕play_button = Button(ai_settings, screen, "Play")
19.開始游戲或重置游戲
- 在game_functions.py中加入監視與按鈕相關的鼠標事件
-
def check_events(ai_settings, screen, ship, bullets, stats: GameStatus, play_button: Button):"""響應按鍵和鼠標事件"""for event in pygame.event.get():# 用戶按下鍵盤if event.type == pygame.KEYDOWN:check_keydown_events(event, ai_settings, screen, ship, bullets)elif event.type == pygame.KEYUP:check_keyup_events(event, ship)elif event.type == pygame.K_SPACE:fire_bullets(ai_settings, )elif event.type == pygame.MOUSEBUTTONDOWN:# 若按下按鈕mouse_x, mouse_y = pygame.mouse.get_pos()check_play_button(stats, play_button, mouse_x, mouse_y) def check_play_button(stats: GameStatus, play_button: Button, mouse_x, mouse_y):"""在玩家單擊play時開始游戲"""if play_button.rect.collidepoint(mouse_x, mouse_y):stats.game_active = True
其中mouse.get_pos返回一個元組,表示鼠標點擊的坐標,我們用play_button.rect.collidepoint方法判斷是否與按鈕坐標重合
-
接下來重置游戲,因為上面僅對第一次點擊有用
-
再次修改check_lpay_button方法
-
def check_play_button(ai_settings, screen, stats: GameStatus, play_button: Button, mouse_x, mouse_y, aliens, ship,bullets):"""在玩家單擊play時開始游戲"""if play_button.rect.collidepoint(mouse_x, mouse_y):# 重置游戲并統計信息stats.reset_status()stats.game_active = True# 清空外星人和子彈的列表bullets.empty()aliens.empty()# 創建外星人,并讓飛船居中create_fleet(ai_settings, screen, ship, aliens)ship.center_ship()
瘋狂外星人小游戲、我們新加了這個方法的參數,不要忘了在調用這個方法的位置加上(pycharm中ctrl+alt+h可以查看調用次方法的方法)
-
現在還是有個問題,如果玩家在點擊按鈕后再次點擊,會出現再次重置的情況,所以我們再加入對stats.game_active的判斷,同時再讓點擊后光標不可見
-
def check_play_button(ai_settings, screen, stats: GameStatus, play_button: Button, mouse_x, mouse_y, aliens, ship,bullets):"""在玩家單擊play時開始游戲"""button_clicked = play_button.rect.collidepoint(mouse_x, mouse_y)if button_clicked and not stats.game_active:#讓光標不可見pygame.mouse.set_visible(False)# 重置游戲并統計信息stats.reset_status()stats.game_active = True# 清空外星人和子彈的列表bullets.empty()aliens.empty()# 創建外星人,并讓飛船居中create_fleet(ai_settings, screen, ship, aliens)ship.center_ship()
修改ship_hit方法,讓游戲重置時,鼠標可見
-
def ship_hit(ai_settings: Settings, status: GameStatus, screen, ship: ship.Ship, aliens, bullets):"""響應外星人撞到飛船"""# 將飛船數量ship_left減一if status.ships_left > 0:status.ships_left -= 1# 清空外星人和子彈aliens.empty()bullets.empty()# 創建一群新的外星人,重置飛船create_fleet(ai_settings, screen, ship, aliens)ship.center_ship()# 暫停sleep(0.5)else:status.game_active = Falsepygame.mouse.set_visible(True)
20.加快游戲節奏
- 我們修改Settings.py中的屬性來加快游戲
-
class Settings():def __init__(self):""" 初始化游戲時的靜態設置"""self.screen_width = 1200self.screen_height = 800self.bg_color = (230, 230, 230)# 飛船設置self.ship_speed_factor = 1.0self.ship_limit = 3# 子彈設置self.bullet_speed_factor = 0.7self.bullet_width = 3self.bullet_height = 15self.bullet_color = 60, 60, 60# 限制子彈數量self.bullets_allowed = 3# 外星人設置self.alien_speed_factor = 0.5 # 外星人水平移動速度self.fleet_drop_speed = 10 # 外星人豎直移動速度self.fleet_direction = 1 # 移動方向: 1為向右,-1向左# 以什么樣的速度加快游戲節奏self.speedup_scale = 1.1self.initialize_dynamic_settings()def initialize_dynamic_settings(self):"""初始化游戲進行而變化的設置"""self.ship_speed_factor = 1.5self.bullet_speed_factor = 3self.alien_speed_factor = 1self.fleet_direction = 1def increase_speed(self):"""提高速度設置"""self.ship_speed_factor *= self.speedup_scaleself.alien_speed_factor *= self.speedup_scaleself.alien_speed_factor *= self.speedup_scale
增加了一個倍率屬性和兩個方法
def check_play_button(ai_settings: Settings, screen, stats: GameStatus, play_button: Button, mouse_x, mouse_y, aliens,ship,bullets):"""在玩家單擊play時開始游戲"""button_clicked = play_button.rect.collidepoint(mouse_x, mouse_y)if button_clicked and not stats.game_active:#重置游戲節奏ai_settings.initialize_dynamic_settings()。。。。。。。。。。。。。。。。。。。。。。。
-
接下來修改
python入侵電腦。game_functions.py中的check_bullet_alien_collision
def check_bullet_alien_collision(ai_settings: Settings, screen, ship, aliens, bullets):# 檢查是否有子彈擊中外星人collisions = pygame.sprite.groupcollide(bullets, aliens, True, True)# 更新外星人if len(aliens) == 0:bullets.empty()#增加游戲節奏ai_settings.increase_speed()create_fleet(ai_settings, screen, ship, aliens)
- 但是現在還有個問題,我們重置游戲時游戲節奏沒有重置
-
def check_play_button(ai_settings: Settings, screen, stats: GameStatus, play_button: Button, mouse_x, mouse_y, aliens,ship,bullets):"""在玩家單擊play時開始游戲"""button_clicked = play_button.rect.collidepoint(mouse_x, mouse_y)if button_clicked and not stats.game_active:#重置游戲節奏ai_settings.initialize_dynamic_settings()
21.計分
- 新增game_status.py中GameStatus類中的屬性
-
def reset_status(self):"""初始化在游戲運行期間可能變化的信息"""self.ships_left = self.ai_settings.ship_limitself.score = 0
新建scoreboard.py模塊,并創建Scoreboard類:
-
class Scoreboard():"""顯示得分信息的類"""def __init__(self, ai_settings: Settings, screen: Surface, status: GameStatus):"""初始化得分涉及的屬性"""self.screen = screenself.screen_rect = screen.get_rect()self.ai_settings = ai_settingsself.status = status# 顯示得分時的字體設置self.text_color = (30, 30, 30)self.font = pygame.font.SysFont(None, 48)# 準備初始得分圖像self.prep_score()def prep_score(self):"""將得分轉換為渲染圖像"""score_str = str(self.status.score)self.score_image = self.font.render(score_str, True, self.text_color)# 將得分顯示在屏幕右上角self.score_rect = self.score_image.get_rect()self.score_rect.right = self.screen_rect.right - 20self.score_rect.top = 20def show_score(self):"""在屏幕上顯示得分"""self.screen.blit(self.score_image, self.score_rect)
22.創建記分牌
- 在主方法中循環前創建得分牌實例
-
# 創建一個記分牌sb = Scoreboard(ai_settings, screen, stats)
并將其傳入循環中的update_screen方法中
-
game_functions.py
-
def update_screen(ai_settings: Settings, screen, stats: GameStatus, ship: ship.Ship, aliens: Group, bullets: Bullet,play_button: Button, sb: Scoreboard):"""更新屏幕上的圖像,并切換到新屏幕"""。。。。。。。。。。。。。。# 顯示得分sb.show_score()# 最近繪制的屏幕可見pygame.display.flip()
接下來我們開始增加分數
-
settings.py中加入分數設置
-
def initialize_dynamic_settings(self):"""初始化游戲進行而變化的設置"""self.ship_speed_factor = 1.5self.bullet_speed_factor = 0.7self.alien_speed_factor = 0.7self.fleet_direction = 1# 計分self.alien_points = 50
- ?game_functions.py中修改方法
def check_bullet_alien_collision(ai_settings: Settings, screen, ship, aliens, bullets, stats: GameStatus,sb: Scoreboard):# 檢查是否有子彈擊中外星人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()# 更新外星人if len(aliens) == 0:bullets.empty()# 增加游戲節奏ai_settings.increase_speed()create_fleet(ai_settings, screen, ship, aliens)
python武裝飛船。其中collisions是一個字典,我們拿到他的值,這個值是一個列表,其中包括我們一顆子彈打掉的全部飛船(不排除一箭雙雕),所以求出列表長度來算分
-
不要忘了在形參中加入新的值并修改調用此方法傳入的參數
-
接下來我們設置游戲難度提高后的點數
-
settings.py
-
class Settings():def __init__(self):。。。。。。。。。。。。。。# 點數提高速度self.score_scale = 1.5def increase_speed(self):。。。。。。。。。。。。。。"""提高點數"""self.alien_points = int(self.alien_points * self.score_scale)
為了讓記分牌跟以前那種街機風格的記分牌一樣,每三位用“,”隔開,我們修改prep_score方法
-
scoreboard.py
-
def prep_score(self):"""將得分轉換為渲染圖像"""# 將得分圓整rounded_score = int(round(self.status.score, -1))score_str = "{:,}".format(rounded_score)# score_str = str(self.status.score)刪去self.score_image = self.font.render(score_str, True, self.text_color)# 將得分顯示在屏幕右上角self.score_rect = self.score_image.get_rect()self.score_rect.right = self.screen_rect.right - 20self.score_rect.top = 20
python入侵個人電腦。其中round()中的-1表示我們向10取整
-
23.顯示最高得分
- scoreboard.py
-
def __init__(self, ai_settings: Settings, screen: Surface, status: GameStatus):"""初始化得分涉及的屬性"""。。。。。。。。。。。。self.prep_high_score()def show_score(self):"""在屏幕上顯示得分"""。。。。。。。。。。。。。。。。。self.screen.blit(self.high_score_image, self.high_score_rect)def prep_high_score(self):"""將最高得分轉換為渲染的圖像"""high_score = int(round(self.status.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_settings.bg_color)# 將最高得分顯示在屏幕中央self.high_score_rect = self.high_score_image.get_rect()self.high_score_rect.centerx = self.screen_rect.centerxself.high_score_rect.top = self.score_rect.top
接下來我們判斷是否誕生了最高分
-
game_functions.py加入
-
def check_high_score(stats: GameStatus, sb: Scoreboard):"""檢查是否誕生了最高分"""if stats.high_score < stats.score:stats.high_score = stats.scoresb.prep_high_score()
我們需要在check_bullet_collision中調用分數判斷
def check_bullet_alien_collision(ai_settings: Settings, screen, ship, aliens, bullets, stats: GameStatus,sb: Scoreboard):# 檢查是否有子彈擊中外星人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)。。。。。。。。。。。。。。。
24、顯示等級
- 增加屬性:
- game_status.py
def reset_status(self):"""初始化在游戲運行期間可能變化的信息"""。。。。。。。。。。。。。self.level = 1
scoreboard.py
-
def __init__(self, ai_settings: Settings, screen: Surface, status: GameStatus):"""初始化得分涉及的屬性"""。。。。。。。。。。。。。。。。self.prep_level() def show_score(self):"""在屏幕上顯示得分"""。。。。。。。。。。。。。。。。。。self.screen.blit(self.level_image, self.level_rect)def prep_level(self):"""將等級渲染為圖像"""self.level_imageself.level_image = self.font.render(str(self.status.level), True, self.text_color, self.ai_settings.bg_color)"""將等級放在得分下方"""self.level_rect = self.level_image.get_rect()self.level_rect.right = self.score_rect.rightself.level_rect.top = self.score_rect.bottom + 10
game_functions.py中修改
-
def check_bullet_alien_collision(ai_settings: Settings, screen, ship, aliens, bullets, stats: GameStatus,sb: Scoreboard):。。。。。。。。。。。。。。。。。。。。。。。。。# 更新外星人if len(aliens) == 0:bullets.empty()# 增加游戲節奏ai_settings.increase_speed()# 如果外星人都被消滅,就提高一個等級stats.level += 1sb.prep_level()create_fleet(ai_settings, screen, ship, aliens)
python小游戲代碼。為了每次點擊play按鈕時重置記分牌,我們修改
-
def check_play_button(ai_settings: Settings, screen, stats: GameStatus, play_button: Button, mouse_x, mouse_y, aliens,ship, bullets, sb: Scoreboard, ):"""在玩家單擊play時開始游戲"""...........................................# 重置得分牌圖像sb.prep_score()sb.prep_high_score()sb.prep_level()# 清空外星人和子彈的列表bullets.empty()aliens.empty()# 創建外星人,并讓飛船居中create_fleet(ai_settings, screen, ship, aliens)ship.center_ship()
我們新傳進來了個參數sb(ScoreBoard類)
-
25.顯示剩余飛船
- ship.py
-
class Ship(Sprite):def __init__(self, screen, ai_settings: Settings):"""初始化飛船,并設置其起始位置"""super(Ship, self).__init__() 。。。。。。。。。。。。。。。。。。。。。。。。。。。。
讓飛船繼承sprite類,這樣我們可以加入編組中管理
-
scoreboard.py類修改
-
class Scoreboard():"""顯示得分信息的類"""def __init__(self, ai_settings: Settings, screen: Surface, status: GameStatus):"""初始化得分涉及的屬性"""。。。。。。。。。。。。。。self.prep_ships()def show_score(self):"""在屏幕上顯示得分"""。。。。。。。。。。。。。。。。。。self.ships.draw(self.screen)def prep_ships(self):"""顯示還剩下多少飛船"""self.ships = Group()for ship_number in range(self.status.ships_left):ship = Ship(self.screen, self.ai_settings)ship.rect.x = 10 + ship_number * ship.rect.widthship.rect.y = 10self.ships.add(ship)
game_functions.py修改,調用prep_ships方法
-
def check_play_button(ai_settings: Settings, screen, stats: GameStatus, play_button: Button, mouse_x, mouse_y, aliens,ship, bullets, sb: Scoreboard, ):"""在玩家單擊play時開始游戲"""。。。。。。。。。。。。。。。。。。# 重置得分牌圖像sb.prep_score()sb.prep_high_score()sb.prep_level()sb.prep_ships()# 清空外星人和子彈的列表bullets.empty()aliens.empty()# 創建外星人,并讓飛船居中create_fleet(ai_settings, screen, ship, aliens)ship.center_ship()
接下來我們在飛船撞到外星人時更新ships編組
-
def ship_hit(ai_settings: Settings, status: GameStatus, screen, ship: ship.Ship, aliens, bullets, sb: Scoreboard):"""響應外星人撞到飛船"""# 將飛船數量ship_left減一if status.ships_left > 0:status.ships_left -= 1# 更新記分牌sb.prep_ships()。。。。。。。。。。。。。。。。。。
我們又加了一個sb參數,按ctrl+alt+h查看調用此方法的函數,依次修改函數形參
-
最終結果
完結撒花,本來沒想到需要這么多字,打的我手疼(哭)。。。。沒有辛勞也有苦勞,祝點贊的各位看官bug少少,頭發多多~~~~