開發一個飛機大戰游戲是Python學習的經典實戰項目,尤其適合結合面向對象編程和游戲框架(如Pygame)進行實踐。以下是游戲設計的核心考慮因素和模塊劃分建議:
一、游戲設計核心考慮因素
-
性能優化
- Python游戲需注意幀率控制(如60FPS)
- 避免頻繁的對象創建/銷毀(使用對象池管理子彈、敵機)
- 減少圖像縮放等實時計算操作(預加載縮放后的圖片)
-
游戲循環(Game Loop)
- 主循環需要處理:事件監聽→狀態更新→畫面渲染→音效播放
- 控制循環頻率(如
pygame.time.Clock().tick(60)
)
-
輸入控制
- 響應鍵盤事件(WSAD/方向鍵移動,空格發射子彈)
- 支持手柄輸入(可選擴展)
-
碰撞檢測
- 使用矩形碰撞(
pygame.Rect.colliderect
) - 優化檢測效率(分組檢測:玩家子彈 vs 敵機、敵機 vs 玩家)
- 使用矩形碰撞(
-
游戲狀態管理
- 區分不同場景:開始界面、游戲中、暫停、結束界面
- 使用狀態機或場景堆棧管理(如
game_state = "playing"
)
-
資源管理
- 集中加載圖片、音效、字體(避免重復IO操作)
- 使用相對路徑確保跨平臺兼容性
-
可擴展性
- 模塊化設計,方便新增敵機類型、武器系統
- 配置數據分離(如敵機屬性存于JSON文件)
二、游戲核心模塊劃分
1. 游戲主模塊(Main Game)
# ====================== 游戲主邏輯 ======================
class Game:def __init__(self):# 初始化顯示self.screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))pygame.display.set_caption("飛機大戰")self.clock = pygame.time.Clock()# 加載資源self.load_resources()# 游戲狀態self.running = Trueself.score = 0def load_resources(self):"""加載所有資源"""global shoot_sound, explosion_soundshoot_sound = load_sound("pew.wav")explosion_sound = load_sound("expl3.wav")# 初始化精靈組self.all_sprites = pygame.sprite.Group()self.enemies = pygame.sprite.Group()self.bullets = pygame.sprite.Group()# 創建玩家self.player = Player()self.all_sprites.add(self.player)# 創建敵機組self.enemy_spawn_timer = pygame.USEREVENT + 1pygame.time.set_timer(self.enemy_spawn_timer, 1000) # 每秒生成敵機def handle_events(self):"""處理事件循環"""for event in pygame.event.get():if event.type == pygame.QUIT:self.running = Falseelif event.type == pygame.KEYDOWN:if event.key == pygame.K_ESCAPE:self.running = Falseelif event.type == self.enemy_spawn_timer:enemy = Enemy()self.all_sprites.add(enemy)self.enemies.add(enemy)def check_collisions(self):"""檢測碰撞事件"""# 子彈擊中敵機hits = pygame.sprite.groupcollide(self.enemies, self.bullets, True, True)for hit in hits:self.score += 50explosion_sound.play()# 敵機撞擊玩家hits = pygame.sprite.spritecollide(self.player, self.enemies, True)for hit in hits:self.player.health -= 1if self.player.health <= 0:self.game_over()def draw_hud(self):"""繪制游戲界面HUD"""# 繪制得分font = pygame.font.Font(None, 36)score_text = font.render(f"Score: {self.score}", True, WHITE)self.screen.blit(score_text, (10, 10))# 繪制生命值health_text = font.render(f"Health: {self.player.health}", True, RED)self.screen.blit(health_text, (10, 50))def game_over(self):"""游戲結束處理"""font = pygame.font.Font(None, 74)text = font.render("GAME OVER", True, RED)text_rect = text.get_rect(center=(SCREEN_WIDTH / 2, SCREEN_HEIGHT / 2))self.screen.blit(text, text_rect)pygame.display.flip()pygame.time.wait(10000) # 等待2秒self.running = Falsedef run(self):"""游戲主循環"""while self.running:# 控制幀率self.clock.tick(FPS)# 處理輸入self.handle_events()keys = pygame.key.get_pressed()if keys[pygame.K_SPACE]:self.player.shoot(self.bullets, self.all_sprites)# 更新游戲狀態self.all_sprites.update(keys) # 更新所有精靈self.check_collisions()# 渲染畫面self.screen.fill(BLACK)self.all_sprites.draw(self.screen)self.draw_hud()pygame.display.flip()pygame.quit()
2. 精靈類(Sprites)
使用面向對象設計游戲元素:
-
Player(玩家飛機)
"""玩家飛機類"""def __init__(self):super().__init__()self.image = load_image("player.png")self.rect = self.image.get_rect(center=(SCREEN_WIDTH / 2, SCREEN_HEIGHT - 50))self.speed = PLAYER_SPEEDself.health = 3self.shoot_delay = 250 # 射擊間隔(毫秒)self.last_shot = pygame.time.get_ticks()def update(self, keys):"""根據鍵盤輸入更新位置"""# 水平移動if keys[pygame.K_LEFT] or keys[pygame.K_a]:self.rect.x -= self.speedif keys[pygame.K_RIGHT] or keys[pygame.K_d]:self.rect.x += self.speed# 垂直移動(可選)if keys[pygame.K_UP] or keys[pygame.K_w]:self.rect.y -= self.speedif keys[pygame.K_DOWN] or keys[pygame.K_s]:self.rect.y += self.speed# 邊界約束self.rect.clamp_ip(pygame.Rect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT))def shoot(self, bullets, all_sprites):"""發射子彈"""now = pygame.time.get_ticks()if now - self.last_shot > self.shoot_delay:self.last_shot = nowbullet = Bullet(self.rect.centerx, self.rect.top)all_sprites.add(bullet)bullets.add(bullet)shoot_sound.play()
-
Enemy(敵機)
def __init__(self):super().__init__()self.image = load_image("enemy1.png")self.rect = self.image.get_rect()self.rect = self.image.get_rect(x=random.randrange(SCREEN_WIDTH - self.rect.width),y=random.randrange(-100, -40),)self.speed_y = random.randint(*ENEMY_SPEED_RANGE)self.speed_x = random.choice([-1, 0, 1]) # 橫向移動def update(self, *args):"""自動向下移動"""self.rect.y += self.speed_yself.rect.x += self.speed_x# 移出屏幕后刪除if self.rect.top > SCREEN_HEIGHT + 10:self.kill()
-
Bullet(子彈)
def __init__(self, x, y):super().__init__()self.image = load_image("bullet3.png")self.rect = self.image.get_rect(center=(x, y))self.speed_y = BULLET_SPEEDdef update(self, *args):"""向上移動"""self.rect.y += self.speed_yif self.rect.bottom < 0: # 移出屏幕后刪除self.kill()
三、推薦技術棧
-
游戲框架
- Pygame:最適合2D游戲入門,文檔豐富
Pygame官方文檔 - Arcade:現代Python游戲庫,面向對象更友好
Arcade官網
- Pygame:最適合2D游戲入門,文檔豐富
-
素材資源
- 免費素材網站:OpenGameArt、Kenney Assets
- 臨時占位素材:可用簡單幾何圖形代替
-
代碼結構參考
- GitHub經典項目:pygame-shmup
- 教程:Pygame飛機大戰教程
四、開發路線建議
-
基礎版本(1-3天)
- 實現玩家移動、發射子彈
- 隨機生成敵機,碰撞檢測得分
- 顯示血量和分數
-
進階版本(3-7天)
- 添加不同敵機類型(普通/快速/BOSS)
- 實現敵機發射子彈
- 增加音效和爆炸動畫
- 支持游戲暫停/繼續
-
擴展版本(可選)
- 添加道具系統(護盾、連發武器)
- 實現關卡進度和難度曲線
- 支持本地高分榜(SQLite存儲)
- 打包為exe/APK文件
五、避坑指南
- 不要過早優化:先完成核心玩法,再考慮性能
- 善用精靈組(Sprite Groups):
pygame.sprite.Group()
管理同類對象 - 坐標系注意:Pygame的Y軸向下增大(與數學坐標系相反)
- 資源路徑問題:使用
os.path
處理路徑,避免絕對路徑硬編碼 - 調試技巧:用
print
輸出變量或繪制調試矩形(pygame.draw.rect
)
通過分階段實現,你將逐步掌握游戲開發的核心模式(狀態機、對象池、事件驅動),同時鞏固Python面向對象編程和模塊化設計能力。
六、總體代碼(單文件)
# -*- coding: utf-8 -*-
import pygame
import random
import os# 初始化Pygame和混音器
pygame.init()
pygame.mixer.init()# 游戲常量配置
SCREEN_WIDTH = 480
SCREEN_HEIGHT = 600
FPS = 60
PLAYER_SPEED = 5
ENEMY_SPEED_RANGE = (2, 4)
BULLET_SPEED = -8 # 玩家子彈速度(向上)# 顏色定義
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
RED = (255, 0, 0)# 資源路徑配置
game_folder = os.path.dirname(__file__)
img_folder = os.path.join(game_folder, "images")
snd_folder = os.path.join(game_folder, "sounds")# 加載圖形資源
def load_image(file):"""加載圖像并轉換格式,返回圖像和矩形"""path = os.path.join(img_folder, file)try:image = pygame.image.load(path).convert()except pygame.error as e:print(f"無法加載圖像: {path}")raise SystemExit(e)image.set_colorkey(BLACK) # 設置透明色return image# 加載音效資源
def load_sound(file):"""加載音效文件"""path = os.path.join(snd_folder, file)try:return pygame.mixer.Sound(path)except pygame.error as e:print(f"無法加載音效: {path}")return None# ====================== 游戲精靈類 ======================
class Player(pygame.sprite.Sprite):"""玩家飛機類"""def __init__(self):super().__init__()self.image = load_image("player.png")self.rect = self.image.get_rect(center=(SCREEN_WIDTH / 2, SCREEN_HEIGHT - 50))self.speed = PLAYER_SPEEDself.health = 3self.shoot_delay = 250 # 射擊間隔(毫秒)self.last_shot = pygame.time.get_ticks()def update(self, keys):"""根據鍵盤輸入更新位置"""# 水平移動if keys[pygame.K_LEFT] or keys[pygame.K_a]:self.rect.x -= self.speedif keys[pygame.K_RIGHT] or keys[pygame.K_d]:self.rect.x += self.speed# 垂直移動(可選)if keys[pygame.K_UP] or keys[pygame.K_w]:self.rect.y -= self.speedif keys[pygame.K_DOWN] or keys[pygame.K_s]:self.rect.y += self.speed# 邊界約束self.rect.clamp_ip(pygame.Rect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT))def shoot(self, bullets, all_sprites):"""發射子彈"""now = pygame.time.get_ticks()if now - self.last_shot > self.shoot_delay:self.last_shot = nowbullet = Bullet(self.rect.centerx, self.rect.top)all_sprites.add(bullet)bullets.add(bullet)shoot_sound.play()class Enemy(pygame.sprite.Sprite):"""敵機基類"""def __init__(self):super().__init__()self.image = load_image("enemy1.png")self.rect = self.image.get_rect()self.rect = self.image.get_rect(x=random.randrange(SCREEN_WIDTH - self.rect.width),y=random.randrange(-100, -40),)self.speed_y = random.randint(*ENEMY_SPEED_RANGE)self.speed_x = random.choice([-1, 0, 1]) # 橫向移動def update(self, *args):"""自動向下移動"""self.rect.y += self.speed_yself.rect.x += self.speed_x# 移出屏幕后刪除if self.rect.top > SCREEN_HEIGHT + 10:self.kill()class Bullet(pygame.sprite.Sprite):"""玩家子彈類"""def __init__(self, x, y):super().__init__()self.image = load_image("bullet3.png")self.rect = self.image.get_rect(center=(x, y))self.speed_y = BULLET_SPEEDdef update(self, *args):"""向上移動"""self.rect.y += self.speed_yif self.rect.bottom < 0: # 移出屏幕后刪除self.kill()# ====================== 游戲主邏輯 ======================
class Game:def __init__(self):# 初始化顯示self.screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))pygame.display.set_caption("飛機大戰")self.clock = pygame.time.Clock()# 加載資源self.load_resources()# 游戲狀態self.running = Trueself.score = 0def load_resources(self):"""加載所有資源"""global shoot_sound, explosion_soundshoot_sound = load_sound("pew.wav")explosion_sound = load_sound("expl3.wav")# 初始化精靈組self.all_sprites = pygame.sprite.Group()self.enemies = pygame.sprite.Group()self.bullets = pygame.sprite.Group()# 創建玩家self.player = Player()self.all_sprites.add(self.player)# 創建敵機組self.enemy_spawn_timer = pygame.USEREVENT + 1pygame.time.set_timer(self.enemy_spawn_timer, 1000) # 每秒生成敵機def handle_events(self):"""處理事件循環"""for event in pygame.event.get():if event.type == pygame.QUIT:self.running = Falseelif event.type == pygame.KEYDOWN:if event.key == pygame.K_ESCAPE:self.running = Falseelif event.type == self.enemy_spawn_timer:enemy = Enemy()self.all_sprites.add(enemy)self.enemies.add(enemy)def check_collisions(self):"""檢測碰撞事件"""# 子彈擊中敵機hits = pygame.sprite.groupcollide(self.enemies, self.bullets, True, True)for hit in hits:self.score += 50explosion_sound.play()# 敵機撞擊玩家hits = pygame.sprite.spritecollide(self.player, self.enemies, True)for hit in hits:self.player.health -= 1if self.player.health <= 0:self.game_over()def draw_hud(self):"""繪制游戲界面HUD"""# 繪制得分font = pygame.font.Font(None, 36)score_text = font.render(f"Score: {self.score}", True, WHITE)self.screen.blit(score_text, (10, 10))# 繪制生命值health_text = font.render(f"Health: {self.player.health}", True, RED)self.screen.blit(health_text, (10, 50))def game_over(self):"""游戲結束處理"""font = pygame.font.Font(None, 74)text = font.render("GAME OVER", True, RED)text_rect = text.get_rect(center=(SCREEN_WIDTH / 2, SCREEN_HEIGHT / 2))self.screen.blit(text, text_rect)pygame.display.flip()pygame.time.wait(10000) # 等待2秒self.running = Falsedef run(self):"""游戲主循環"""while self.running:# 控制幀率self.clock.tick(FPS)# 處理輸入self.handle_events()keys = pygame.key.get_pressed()if keys[pygame.K_SPACE]:self.player.shoot(self.bullets, self.all_sprites)# 更新游戲狀態self.all_sprites.update(keys) # 更新所有精靈self.check_collisions()# 渲染畫面self.screen.fill(BLACK)self.all_sprites.draw(self.screen)self.draw_hud()pygame.display.flip()pygame.quit()if __name__ == "__main__":game = Game()game.run()
附件:圖片資源
音效資源無法放置在此處,如自行下載。