python實現飛機大戰遊戲(pygame版)
簡介
使用python實現pygame版的飛機大戰遊戲;
環境:Windows系統+python3.8.0
遊戲規則:
1.點選“PLAY”或者按鍵“P”開始遊戲;
2.敵機根據設定頻率從頂部隨機位置生成,生成後向下移動;
3.飛船在底部中間生成,玩家使用上下左右鍵控制飛船移動,敲擊空格鍵發射子彈;
4.子彈打到敵機,該敵機產生爆炸效果並累計分數到右上角;
5.消滅10只飛機後,等級升高,敵機生成頻率變快,下落速度也變快;
6.當三條命都消失了,遊戲結束。
遊戲執行效果如下:
實現過程
1.新建檔案“file.py”,用來儲存資訊到檔案和讀取檔案的資訊,本例用來儲存和讀取最高分;
import pickle # filename = 'file/stats.pkl' # 儲存資訊到檔案 def save_file(obj,filename): statsObj = load_file(filename) if statsObj == 0: # 不存在檔案時,直接儲存字典 with open(filename,'wb') as f: pickle.dump(obj,f,pickle.HIGHEST_PROTOCOL) else: # 存在檔案時,只修改檔案中的最高分 for key,val in statsObj.items(): # 獲取檔案最高分的值(當檔案欄位不止一個時候使用) if key == 'highScore': statsObj[key] = obj['highScore'] obj = statsObj with open(filename,'wb') as f: pickle.dump(obj,pickle.HIGHEST_PROTOCOL) # 讀取資訊 def load_file(filename): try: with open(filename,'rb') as f: return pickle.load(f) except FileNotFoundError: # 不存在檔案則輸入錯誤資訊 msg = "Sorry,the file " + filename + " does not exist." print(msg) return 0 # obj = {'highScore': 20,'points': 5} # obj = {'highScore': 50} # save_file(obj,filename) # filedata = load_file(filename) # print(filedata)
2.k新建檔案settings.py,用來定義一些必須的基本屬性和初始值;
import file as f class Settings(): def __init__(self): self.screen_width = 480 self.screen_height = 660 self.bg_color = (230,230,230) # 子彈設定(寬、高、顏色、最大數量) self.bullet_width = 5 self.bullet_height = 15 self.bullet_color = 255,255,255 # 敵機移動頻率 self.enemy_frequency = 0 # 加快遊戲節奏的速度 self.speedup_scale = 1.1 # 分數的提高速度 self.score_scale = 1.5 self.initialize_settings() # 初始化統計資訊 self.reset_stats() # 統計資訊檔案路徑 self.filename = 'file/stats.pkl' # 遊戲剛啟動時處於非活動狀態 self.game_active = False # 讀取檔案的最高分,在任何情況下都不應重置最高得分 statsObj = f.load_file(self.filename) if statsObj == 0: # 不存在檔案則顯示最高分0 highScore = 0 else: for key,val in statsObj.items(): # 獲取檔案最高分的值(當檔案欄位不止一個時候使用) if key == 'highScore': highScore = val self.high_score = highScore def initialize_settings(self): """初始化隨遊戲進行而變化的設定""" self.player_move_speed = 2.5 self.bullet_speed = 3 self.enemy_move_speed = 1 # 記分 self.one_points = 50 def increase_speed(self): """提高速度設定""" # self.player_move_speed *= self.speedup_scale self.bullet_speed *= self.speedup_scale self.enemy_move_speed *= self.speedup_scale self.one_points = int(self.one_points * self.score_scale) def reset_stats(self): """初始化在遊戲執行期間可能變化的統計資訊""" # 可射失的數量 self.player_limit = 3 # 射擊分數 self.score = 0 # 等級 self.level = 1 # 打中多少矩形升一級 self.level_number = 10 # 生成敵機頻率間隔 self.enemy_frequency_space = 50
3.新建檔案enemy.py,用來定義敵機類(位置topleft隨機生成)和宣告方法move;
import pygame import random from pygame.sprite import Sprite class Enemy(Sprite): def __init__(self,enemy_down_imgs,settings): super(Enemy,self).__init__() self.image = pygame.image.load('images/enemy1.png') self.rect = self.image.get_rect() self.rect.topleft = [random.randint(0,settings.screen_width - self.rect.width),0] self.down_imgs = enemy_down_imgs self.speed = settings.enemy_move_speed self.down_index = 0 # 敵機移動,邊界判斷及刪除在遊戲主迴圈裡處理 def move(self): self.rect.top += self.speed
4.新建檔案player.py,用來定義玩家類(可上下左右移動)和相應的方法;
import pygame from pygame.sprite import Sprite class Player(Sprite): def __init__(self,settings,screen): super(Player,self).__init__() self.settings = settings self.screen = screen self.screen_rect = self.screen.get_rect() # 引入飛船圖片並定位 self.image = pygame.image.load('images/player.png') self.rect = self.image.get_rect() self.rect.centerx = self.screen_rect.centerx self.rect.bottom = self.screen_rect.bottom # 移動標誌 self.move_left = False self.move_right = False self.move_down = False self.move_up = False def rotate(self,angle): # 圖片旋轉 self.image = pygame.transform.rotate(self.image,angle) def scale(self,multiple): # 圖片縮放 self.image = pygame.transform.smoothscale(self.image,(multiple,multiple)) def update(self): if self.move_left and self.rect.left > self.screen_rect.left: self.rect.centerx -= self.settings.player_move_speed if self.move_right and self.rect.right < self.screen_rect.right: self.rect.centerx += self.settings.player_move_speed if self.move_down and self.rect.bottom < self.screen_rect.bottom: self.rect.centery += self.settings.player_move_speed if self.move_up and self.rect.top > 0: self.rect.centery -= self.settings.player_move_speed def draw_player(self): """繪製飛船到螢幕""" self.screen.blit(self.image,self.rect)
5.新建檔案“bullet.py”,用來定義子彈類(位置在飛船的頂部,並往上移動)和相應的方法;
import pygame from pygame.sprite import Sprite class Bullet(Sprite): """ 一個對飛船發射的子彈進行管理的類 """ def __init__(self,screen,player): """ 在飛船所處的位置建立一個子彈物件 """ super(Bullet,self).__init__() self.screen = screen # 在 (0,0) 處建立一個表示子彈的矩形,再設定正確的位置 self.rect = pygame.Rect(0,settings.bullet_width,settings.bullet_height) self.rect.centerx = player.rect.centerx # 飛船頂部 self.rect.bottom = player.rect.top # 儲存用小數表示的子彈位置 self.y = float(self.rect.y) self.color = settings.bullet_color self.speed = settings.bullet_speed def update(self): """向上移動子彈""" # 更新表示子彈位置的小數值(子彈往右) self.y -= self.speed # 更新表示子彈的rect的位置 self.rect.y = self.y def draw_bullet(self): """在螢幕上繪製子彈""" pygame.draw.rect(self.screen,self.color,self.rect)
6.新建檔案“button.py”,用來定義按鈕類和相應方法,本例使用於繪製“PLAY”按鈕;
import pygame.font class Button(): def __init__(self,msg): """初始化按鈕的屬性""" self.screen = screen self.screen_rect = screen.get_rect() # 設定按鈕的尺寸和其他屬性 self.width,self.height = 100,30 self.button_color = (216,30,6) self.text_color = (255,255) self.font = pygame.font.SysFont(None,36) # 建立按鈕的rect物件,並使其居中 self.rect = pygame.Rect(0,self.width,self.height) self.rect.center = self.screen_rect.center # 按鈕的標籤只需建立一次 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): # 繪製一個用顏色填充的按鈕,再繪製文字 self.screen.fill(self.button_color,self.rect) self.screen.blit(self.msg_image,self.msg_image_rect)
7.新建檔案“scoreboard.py”,用來定義記分板,本例使用於繪製左上角飛船(生命數)、頂部中間的“最高分”、右上角的“積分”和“等級”;
import pygame.font from pygame.sprite import Group from player import Player class Scoreboard(): """顯示得分資訊的類""" def __init__(self,screen): """初始化顯示得分涉及的屬性""" self.screen = screen self.screen_rect = screen.get_rect() self.settings = settings # 顯示得分資訊時使用的字型設定 self.text_color = (255,30) # 飛船縮放值 self.scaleValue = 20 # 準備初始得分影象\最高得分\等級 self.prep_score() self.prep_high_score() self.prep_level() self.prep_players() def prep_score(self): """將得分轉換為渲染的影象""" rounded_score = int(round(self.settings.score,-1)) score_str = '{:,}'.format(rounded_score) self.score_image = self.font.render(score_str,self.text_color) # 將得分放在螢幕右上角 self.score_rect = self.score_image.get_rect() self.score_rect.right = self.screen_rect.right -20 self.score_rect.top = 10 def prep_high_score(self): """ 將最高得分轉換為渲染的影象 """ high_score = int(round(self.settings.high_score,-1)) high_score_str = "{:,}".format(high_score) self.high_score_image = self.font.render(high_score_str,self.text_color) # 將最高得分放在螢幕頂部中央 self.high_score_rect = self.high_score_image.get_rect() self.high_score_rect.centerx = self.screen_rect.centerx self.high_score_rect.top = self.score_rect.top def prep_level(self): """將等級轉換為渲染的影象""" self.level_image = self.font.render(str(self.settings.level),self.text_color) # 將等級放在得分下方 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 def prep_players(self): """ 顯示還餘下多少艘飛船 """ self.players = Group() for player_number in range(self.settings.player_limit): player = Player(self.settings,self.screen) # 縮放球大小並賦值位置 player.scale(self.scaleValue) player.rect.x = 10 + player.rect.width * player_number * 0.5 player.rect.y = self.score_rect.top self.players.add(player) 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.players.draw(self.screen)
8.新建檔案“game_functions.py”,存放跟遊戲有關的所有業務邏輯函式(程式碼有詳細的註釋資訊);
import sys import pygame from bullet import Bullet from enemy import Enemy import file as f # 事件 def check_events(settings,player,play_button,scoreboard,bullets,fireSound): """ 響應按鍵和滑鼠事件 """ for event in pygame.event.get(): if event.type == pygame.QUIT: save_file(settings) sys.exit() elif event.type == pygame.KEYDOWN: check_keydown_events(event,fireSound) elif event.type == pygame.KEYUP: check_keyup_events(event,player) elif event.type == pygame.MOUSEBUTTONDOWN: mouse_x,mouse_y = pygame.mouse.get_pos() check_play_button(settings,mouse_x,mouse_y) def check_keydown_events(event,fireSound): """ 響應按鍵 """ if event.key == pygame.K_DOWN: player.move_down = True elif event.key == pygame.K_UP: player.move_up = True elif event.key == pygame.K_LEFT: player.move_left = True elif event.key == pygame.K_RIGHT: player.move_right = True elif event.key == pygame.K_SPACE: fireSound.play() # 點選空格鍵建立一顆子彈 fire_bullet(settings,bullets) elif event.key == pygame.K_p: start_game(settings,scoreboard) elif event.key == pygame.K_q: save_file(settings) sys.exit() def check_keyup_events(event,player): """ 響應鬆開 """ if event.key == pygame.K_DOWN: player.move_down = False elif event.key == pygame.K_UP: player.move_up = False elif event.key == pygame.K_LEFT: player.move_left = False elif event.key == pygame.K_RIGHT: player.move_right = False def check_play_button(settings,mouse_y): """在玩家單擊Play按鈕時開始新遊戲""" button_clicked = play_button.rect.collidepoint(mouse_x,mouse_y) if button_clicked and not settings.game_active: start_game(settings,scoreboard) def start_game(settings,scoreboard): """開始遊戲""" # 重置遊戲設定 settings.initialize_settings() # 隱藏游標 pygame.mouse.set_visible(False) # 重置遊戲統計資訊 settings.reset_stats() settings.game_active = True # 重置記分牌影象 scoreboard.prep_score() scoreboard.prep_high_score() scoreboard.prep_level() scoreboard.prep_players() def save_file(settings): # 保持檔案 obj = {'highScore': settings.high_score} f.save_file(obj,settings.filename) # 敵機 def update_enemies(settings,enemies,enemies_down,explosiveSound): # 生成敵機,需要控制生成頻率 if settings.enemy_frequency % settings.enemy_frequency_space == 0: enemy1 = Enemy(enemy_down_imgs,settings) enemies.add(enemy1) settings.enemy_frequency += 1 if settings.enemy_frequency >= 100: settings.enemy_frequency = 0 for enemy in enemies: # 移動敵機 enemy.move() # 敵機與玩家飛機碰撞效果處理 兩個精靈之間的圓檢測 if pygame.sprite.collide_circle(enemy,player): enemies_down.add(enemy) enemies.remove(enemy) settings.player_limit -= 1 scoreboard.prep_players() break # 移動出屏幕後刪除飛機 if enemy.rect.top < 0: enemies.remove(enemy) # 敵機被子彈擊中效果處理 # 將被擊中的敵機物件新增到擊毀敵機 Group 中,用來渲染擊毀動畫 # 方法groupcollide()是檢測兩個精靈組中精靈們的矩形衝突 enemies1_down = pygame.sprite.groupcollide(enemies,True) if enemies1_down: explosiveSound.play() # 計算分數並渲染 for enemys in enemies1_down.values(): settings.score += settings.one_points * len(enemys) scoreboard.prep_score() # 渲染最高分 check_high_score(settings,scoreboard) # 等達到等級數量升級並渲染新等級 settings.level_number -= 1 if settings.level_number == 0: settings.increase_speed() settings.level += 1 scoreboard.prep_level() # 還原為4(同settings一致) settings.level_number = 10 # 加快生成敵機 if settings.enemy_frequency_space > 10: settings.enemy_frequency_space -= 10 # 遍歷key值 返回的碰撞敵機 for enemy_down in enemies1_down: # 點選銷燬的敵機到列表 enemies_down.add(enemy_down) # 敵機被子彈擊中效果顯示 for enemy_down in enemies_down: if enemy_down.down_index == 0: pass if enemy_down.down_index > 7: enemies_down.remove(enemy_down) continue #顯示碰撞圖片 screen.blit(enemy_down.down_imgs[enemy_down.down_index // 2],enemy_down.rect) enemy_down.down_index += 1 # 顯示精靈 enemies.draw(screen) # 子彈 def fire_bullet(settings,bullets): """建立子彈""" new_bullet = Bullet(settings,player) bullets.add(new_bullet) def update_bullets(screen,bullets): """更新子彈的位置,並刪除已消失的子彈""" # 更新子彈的位置 bullets.update() # 刪除已消失的子彈並同時更新飛船的生命 for bullet in bullets.copy(): if bullet.rect.top < screen.get_rect().top: bullets.remove(bullet) # 分數 def check_high_score(settings,scoreboard): """檢查是否誕生了新的最高得分""" if settings.score > settings.high_score: settings.high_score = settings.score scoreboard.prep_high_score() # 螢幕 def update_screen(settings,bullets): """ 更新螢幕上的影象,並切換到新螢幕 """ # 繪製飛船到螢幕 player.draw_player() # 繪製子彈到螢幕 for bullet in bullets.sprites(): bullet.draw_bullet() # 渲染記分牌資訊 scoreboard.show_score() # if settings.player_limit == 0: settings.game_active = False settings.reset_stats() # 清空矩形列表和子彈列表 enemies.empty() bullets.empty() screen_rect = screen.get_rect() player.rect.centerx = screen_rect.centerx player.rect.bottom = screen_rect.bottom # 如果遊戲處於非活動狀態,就繪製 Play 按鈕 if not settings.game_active: play_button.draw_button() # 讓最近繪製的螢幕可見 pygame.display.flip()
9.新建檔案shootingenemy.py,主函式用來初始化程式,並同步更新程式的資訊;
import pygame from pygame.sprite import Group from settings import Settings from button import Button from player import Player import game_functions as gf from scoreboard import Scoreboard def run_game(): pygame.init() # 初始化全部音訊,並載入爆炸聲音樂 pygame.mixer.init() # 等待1s pygame.time.delay(1000) pygame.mixer.music.load('file/bgsound.mp3') # -1代表無限迴圈(背景音樂) pygame.mixer.music.play(-1) # 爆炸聲 explosiveSound = pygame.mixer.Sound('file/explosiveSound.wav') # 槍聲 fireSound = pygame.mixer.Sound('file/fireSound.wav') # 遊戲迴圈幀率設定 clock = pygame.time.Clock() settings = Settings() screen = pygame.display.set_mode((settings.screen_width,settings.screen_height)) # 全屏顯示 # screen = pygame.display.set_mode((0,0),pygame.FULLSCREEN) pygame.display.set_caption('飛機大戰') # 左上角圖示 ic_launcher = pygame.image.load('images/ic_launcher.png').convert_alpha() pygame.display.set_icon(ic_launcher) # 背景圖 background = pygame.image.load('images/background.png').convert_alpha() # 敵機圖片 enemy_img1= pygame.image.load('images/enemy1.png') enemy_img2= pygame.image.load('images/enemy2.png') enemy_img3= pygame.image.load('images/enemy3.png') enemy_img4= pygame.image.load('images/enemy4.png') # 敵機不同狀態的圖片列表,多張圖片展示為動畫效果 enemy_down_imgs = [] enemy_down_imgs.append(enemy_img1) enemy_down_imgs.append(enemy_img2) enemy_down_imgs.append(enemy_img3) enemy_down_imgs.append(enemy_img4) # 儲存敵機 enemies = Group() # 儲存被擊毀的飛機,用來渲染擊毀動畫 enemies_down = Group() # 建立Play按鈕 play_button = Button(screen,'Play') # 建立飛船 player = Player(settings,screen) # 建立子彈的編組 bullets = Group() # 建立記分牌 scoreboard = Scoreboard(settings,screen) while True: # 繪製背景 screen.blit(background,(0,0)) # 控制遊戲最大頻率 clock.tick(60) # 檢查玩家輸入(不加會導致一直載入) gf.check_events(settings,fireSound) if settings.game_active: # 更新飛船位置 player.update() # 更新敵機 gf.update_enemies(settings,explosiveSound) # 更新子彈位置 gf.update_bullets(screen,bullets) # 更新螢幕資訊 gf.update_screen(settings,bullets) run_game(),
10.在檔案shootingenemy.py目錄路徑下,執行命令“python shootingenemy.py”彈出視窗,即可對其操作遊玩。
結語
該遊戲加入了背景音樂、射擊聲、子彈射中敵機的爆炸聲和爆炸效果、生命數、積分、等級、最高分和開始按鈕等元素,大家也可以自行加入其它好玩的元素。
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支援我們。