1. 程式人生 > 程式設計 >python實現飛機大戰遊戲(pygame版)

python實現飛機大戰遊戲(pygame版)

簡介

使用python實現pygame版的飛機大戰遊戲;

環境:Windows系統+python3.8.0

遊戲規則:

1.點選“PLAY”或者按鍵“P”開始遊戲;

2.敵機根據設定頻率從頂部隨機位置生成,生成後向下移動;

3.飛船在底部中間生成,玩家使用上下左右鍵控制飛船移動,敲擊空格鍵發射子彈;

4.子彈打到敵機,該敵機產生爆炸效果並累計分數到右上角;

5.消滅10只飛機後,等級升高,敵機生成頻率變快,下落速度也變快;

6.當三條命都消失了,遊戲結束。

遊戲執行效果如下:

python實現飛機大戰遊戲(pygame版)

實現過程

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”彈出視窗,即可對其操作遊玩。

結語

該遊戲加入了背景音樂、射擊聲、子彈射中敵機的爆炸聲和爆炸效果、生命數、積分、等級、最高分和開始按鈕等元素,大家也可以自行加入其它好玩的元素。

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支援我們。