暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

Python游戏

K记忆 2020-11-15
317

文章流程

  • 一、项目环境背景介绍

    • 1.Pycharm版本:社区2017.2.7版本

    • 2.对应python版本:3.6.4版本

    • 3.基于以上环境开发一个游戏

    • 4.游戏项目的目录结构如下

  • 二、项目过程中所有的.py文件代码

    • 1.alien_invasion.py(主文件)

    • 2.game_functions.py(功能函数)

    • 3.alien.py(外星人)

    • 4.ship.py(飞船)

    • 5.bullet.py(子弹)

    • 6.button.py(play按钮)

    • 7.settings.py(游戏属性设置)

    • 8.scoreboard.py(分数)

    • 9.game_stats.py(游戏状态)

    • 10.music.py(音效)

    • 11.游戏图片/音效素材获取

    • 12.针对游戏过程中各种报错解决办法思路的提醒

    • 13.游戏完成阶段总结

  • 三、主.py文件转可执行.exe文件

    • 1.安装pyinstaller:

    • 2.主.py文件转可执行.exe文件

    • 3.转后事件处理

  • 四、报错情况分析以及解决办法

    • 1.双击alien_invasion.exe执行文件出现闪退

    • 2.双击alien_invasion.exe执行文件弹出“Faied to execute script ***”错误

  • 五、压缩.exe相关素材


一、项目环境背景介绍

1.Pycharm版本:社区2017.2.7版本

2.对应python版本:3.6.4版本

环境搭建的帖子(这位哥们写得很细的 点赞):https://blog.csdn.net/wardseptember/article/details/79965836

3.基于以上环境开发一个游戏

在游戏《外星人入侵》中,玩家控制着一艘最初出现在屏幕底部中央的飞船。玩家可以使用箭头键左右移动飞船,还可使用空格键进行射击。游戏开始时,一群外星人出现在天空中,他们在屏幕中向下移动。玩家的任务是射杀这些外星人。玩家将所有外星人都消灭干净后,将出现一群新的外星人,他们移动的速度更快。只要有外星人撞到了玩家的飞船或到达了屏幕底部,玩家就损失一艘飞船。玩家损失三艘飞船后,游戏结束。(本游戏附加各种音效)

4.游戏项目的目录结构如下

>
复制

>D\Python-Projects

>a book of py

>Projects

>Project 1(alien_invasion) chapter 12-14

>alien_invasion

>images

>alien.bmp

>ship.bmp

>musics

>Bullet_biu.wav

>Explo_Large.wav

>Explo_Small.wav

>order_music.mp3

>alien_invasion.py(主文件)

>game_functions.py(功能函数)

>alien.py(外星人)

>ship.py(飞船)

>bullet.py(子弹)

>button.py(play按钮)

>settings.py(游戏属性设置)

>scoreboard.py(分数)

>game_stats.py(游戏状态)

>music.py(音效)

>Max_score.json(历史最高分记录文件)

二、项目过程中所有的.py文件代码

1.alien_invasion.py(主文件)

# coding: UTF-8
# 项目1:外星人入侵

# 系统自带的类或函数
# import sys # 退出游戏----集中在game_functions.py中使用,故这注释掉
import pygame   # 含有开发游戏所需功能
from pygame.sprite import Group     # 存储所有有效子弹的类

# 自定义的类或函数
from settings import Settings   # 对《外星人入侵》游戏中所有设置的类,如屏幕宽高…
from ship import Ship   # 创建飞船的类
from button import Button   # 创建按钮的类
from game_stats import Game_Stats   # 创建跟踪游戏统计信息的类
from scoreboard import Scoreboard   # 创建得分类
from music import bg_music  # 背景音乐
import game_functions as gf     # 所有的功能函


def run_game():
   # 初始化游戏并创建一个屏幕对象
   pygame.init()
   ai_settings = Settings()
   screen = pygame.display.set_mode(
      (ai_settings.screen_width, ai_settings.screen_height))
   pygame.display.set_caption("外星人入侵")

   # 初始化声音播放模块
   pygame.mixer.init()

   # 创建Play按钮
   play_button = Button(ai_settings, screen, "Play")

   # 创建一艘飞船
   ship = Ship(ai_settings, screen)

   # 创建一个用于存储子弹的编组
   bullets = Group()

   # 创建一个用于存储外星人的编组
   aliens = Group()

   # 创建存储游戏统计信息的实例
   game_stats = Game_Stats(ai_settings)

   # 创建记分牌
   scoreb = Scoreboard(ai_settings, screen, game_stats)

   # 创建外星人群
   gf.create_fleet(ai_settings, screen, ship, aliens)

   # 加载背景音乐
   bg_music()

   # 开始游戏的主循环
   while True:

       # 调用响应鼠标和键盘事件的函数
       gf.check_events(ai_settings, screen, game_stats, scoreb, play_button, ship, aliens, bullets)

       if game_stats.game_active:

           # 调用背景音乐
           gf.play_bg_music()
           # 调用飞船水平持续移动的函数
           ship.update()

           # 调用关于子弹相关操作的函数
           gf.update_bullets(ai_settings, screen, game_stats, scoreb, ship, aliens, bullets)

           # 调用外星人向右移动的函数
           gf.update_aliens(ai_settings, game_stats, scoreb, screen, ship, aliens, bullets)

       # 调用更新屏幕上的图像并切换到新屏幕的函数
       gf.update_screen(ai_settings, screen, game_stats, scoreb, ship, aliens, bullets, play_button)


run_game()  # 此时运行的话 会弹出一个pygame窗口
复制

2.game_functions.py(功能函数)

# coding: UTF-8
# 《外星人入侵》运行的所有函数

import sys
import pygame

from bullet import Bullet
from alien import Alien
from time import sleep
import json
import music


def play_bg_music():
   """背景音乐"""
   if not pygame.mixer.music.get_busy():
       pygame.mixer.music.play()


def check_keydown_events(event, ai_settings, screen, ship, bullets, game_stats, scoreb, aliens):
   """"
      响应鼠标按下操作
  """
   # 按右箭头飞船向右移动
   if event.key == pygame.K_RIGHT:
       ship.moving_right = True
   # 按左箭头飞船向左移动
   elif event.key == pygame.K_LEFT:
       ship.moving_left = True

   # 按空格键创建一颗子弹并将其加入到编组bullets中
   elif event.key == pygame.K_SPACE:
       fire_bullet(ai_settings, screen, ship, bullets)

   # 按p开始游戏
   elif event.key == pygame.K_p:
       start_game(ai_settings, screen, ship, bullets, game_stats, scoreb,
                  aliens)

   # 按z暂停游戏3s
   elif event.key == pygame.K_z:
       sleep(2)

   # 按q退出游戏并把最高分写入文件
   elif event.key == pygame.K_q:
       with open('Max_score.json', 'w', encoding='UTF-8') as file:
           json.dump(game_stats.high_score, file)
       sys.exit()


def fire_bullet(ai_settings, screen, ship, bullets):
   """
      按照要求发射子弹数量
  """
   if len(bullets) < ai_settings.bullet_allowed:
       music.bullet_biu()                              # 发射子弹的声音
       new_bullet = Bullet(ai_settings, screen, ship)  # 如果还没有到达限制,就发射一颗子弹
       bullets.add(new_bullet)                         # 创建一颗子弹,并将其加入到编组bullets中


def start_game(ai_settings, screen, ship, bullets, game_stats, scoreb,
              aliens):
   """
      P264中动手试一试14-1的练习:让玩家按p开始游戏
  """
   # 重置游戏统计信息
   game_stats.reset_stats()
   game_stats.game_active = True

   # 重置记分牌图像
   scoreb.prep_score()
   scoreb.prep_high_score()
   scoreb.prep_level()
   scoreb.prep_ships()

   # 清空外星人列表和子弹列表
   aliens.empty()
   bullets.empty()

   # 创建一群新的外星人,并让飞船居中
   create_fleet(ai_settings, screen, ship, aliens)
   ship.center_ship()

   # 暂停让用户反应一会
   sleep(0.5)


def check_keyup_events(event, ship):
   """"
      响应鼠标松开---飞船停下
  """
   if event.key == pygame.K_RIGHT:
       ship.moving_right = False

   elif event.key == pygame.K_LEFT:
       ship.moving_left = False


def check_play_button(ai_settings, screen, game_stats, scoreb, play_button, ship,
                     aliens, bullets, mouse_x, mouse_y):
   """
      在玩家单击Play按钮时开始游戏
  """
   button_clicked = play_button.button_rect.collidepoint(mouse_x, mouse_y)
   # 单击Play按钮且游戏处于非活跃状态时----避免了游戏处于活跃状态下单击到了Play按钮区域重启游戏
   if button_clicked and not game_stats.game_active:
       """如果鼠标单击位置在msg_image_rect范围内则将游戏置于活跃状态"""

       # # 重置游戏设置
       ai_settings.initialize_dynamic_settings()

       # 游戏开始后Play按钮隐藏起来
       pygame.mouse.set_visible(False)

       start_game(ai_settings, screen, ship, bullets, game_stats, scoreb, aliens)


def check_events(ai_settings, screen, game_stats, scoreb, play_button, ship, aliens, bullets):
   """
      响应鼠标和键盘事件
  """
   # 游戏退出并把最高分写入文件
   for event in pygame.event.get():
       if event.type == pygame.QUIT:
           with open('Max_score.json', 'w', encoding='UTF-8') as file:
               json.dump(game_stats.high_score, file)
           sys.exit()

       # 响应Play按钮操作
       elif event.type == pygame.MOUSEBUTTONDOWN:
           mouse_x, mouse_y = pygame.mouse.get_pos()   # 该函数返回一个元组--获取鼠标单击Play按钮时的位置
           check_play_button(ai_settings, screen, game_stats, scoreb, play_button, ship,
                             aliens, bullets, mouse_x, mouse_y)

       # 判读飞船向左还是向右移动
       elif event.type == pygame.KEYDOWN:
           check_keydown_events(event, ai_settings, screen, ship, bullets, game_stats, scoreb, aliens)

       # 飞船停下
       elif event.type == pygame.KEYUP:
           check_keyup_events(event, ship)


def update_screen(ai_settings, screen, game_stats, scoreb, ship, aliens, bullets, play_button):
   """
      更新屏幕上的图像并切换到新屏幕
  """
   # 每次循环时都重绘屏幕
   screen.fill(ai_settings.bg_color)   # 先填充背景后绘制飞船
   ship.blitem()
   aliens.draw(screen)

   # 在飞船后重绘所有子弹
   for bullet in bullets.sprites():
       bullet.draw_bullet()
   # 显示得分
   scoreb.show_score()

   # 如果游戏处于非活动状态就绘制Play按钮
   if not game_stats.game_active:
       play_button.draw_button()

   # 让最近绘制的屏幕可见
   pygame.display.flip()


def start_new_level(ai_settings, screen, game_stats, scoreb, ship, aliens, bullets):
   """
      当消灭干净外星人提高一个等级
  """
   if len(aliens) == 0:
       # 删除现有子弹
       bullets.empty()

       # 逐渐提高速度加快游戏节奏
       ai_settings.increase_speed()

       # 当前屏幕外星人全部被消灭就提高一个等级
       game_stats.level += 1
       scoreb.prep_level()

       # 创建一群新的外星人
       create_fleet(ai_settings, screen, ship, aliens)  # 调用创建外星人群的函数


def check_bullet_alien_collisions(ai_settings, screen, game_stats, scoreb, ship, aliens, bullets):
   """子弹与外星人相撞后的操作"""
   # 检查是否有子弹击中外星人
   # 如果击中了就删除相应的子弹与外星人
   collisions = pygame.sprite.groupcollide(bullets, aliens, True, True)
   """方法sprite.groupcollide()检查两个编组的成员之间的碰撞(碰撞是指游戏元素重叠在一起):
  将每颗子弹同每个外星人的rect作比较 并返回一个字典 字典中的键为子弹 值为被击中的外星人"""

   # 每消灭一个外星人都将加一个points且显示最新得分的图像
   if collisions:
       music.voice_small()                 # 子弹与外星人相撞的声音
       for aliens in collisions.values():  # aliens指被同一颗子弹击中的外星人---是一个列表
           game_stats.score += ai_settings.alien_points * len(aliens)
           scoreb.prep_score()
       check_high_score(game_stats, scoreb)

   start_new_level(ai_settings, screen, game_stats, scoreb, ship, aliens, bullets)


def update_bullets(ai_settings, screen, game_stats, scoreb, ship, aliens, bullets):
   """
      更新子弹位置并删除已消失的子弹
  """
   # 更新子弹位置
   bullets.update()

   # 删除已消失的子弹
   for bullet in bullets.copy():
       if bullet.rect.bottom <= 0:  # 当子弹底部越过屏幕顶部(0)时删除子弹
           bullets.remove(bullet)
   check_bullet_alien_collisions(ai_settings, screen, game_stats, scoreb, ship, aliens, bullets)


def get_number_aliens_X(ai_settings, alien_width):
   """
      计算每行可容纳多少个外星人
  """
   availabble_space_x = ai_settings.screen_width - 2 * alien_width  # 一行可可容纳的水平长度
   number_aliens_x = int(availabble_space_x / (2 * alien_width))  # 一行可容纳多少个外星人
   return number_aliens_x


def get_number_rows(ai_settings, alien_height, ship_height):
   """
      计算屏幕可容纳多少行外星人
  """
   availables_space_y = (ai_settings.screen_height-ship_height-
                        (3*alien_height))
   number_rows = int(availables_space_y / (2 * alien_height))
   return number_rows


def create_alien(ai_settings, screen,  aliens, alien_number, row_number):
   """
      创建一个外星人并将其放在当前行
  """
   alien = Alien(ai_settings, screen)
   alien_width = alien.rect.width
   alien_height = alien.rect.height + 3    # 让外星人之间间隔大些
   alien.x = alien_width + 2 * alien_width * alien_number  # 获取新建外星人所移动的位置
   alien.rect.x = alien.x  # 新建外星人的位置
   alien.rect.y = alien_height + 2 * alien_height * row_number  # 新行的位置
   aliens.add(alien)


def create_fleet(ai_settings, screen, ship, aliens):
   """
      创建外星人群
  """
   # 创建一个外星人并计算一行可容纳多少个外星人
   # 外星人间距为外星人的宽度
   alien = Alien(ai_settings, screen)
   number_aliens_x = get_number_aliens_X(ai_settings, alien.rect.width)  # 一行可容纳外星人的个数
   number_rows = get_number_rows(ai_settings, alien.rect.height,
                                 ship.rect.height)   # 屏幕上可容纳外星人的行数

   # 内外双循环创建外星人群
   for row_number in range(number_rows):       # 外循环创建外星人行数
       for alien_number in range(number_aliens_x):     # 内循环创建外星人
           create_alien(ai_settings, screen, aliens, alien_number, row_number)  # 调用创建外星人的函数


def check_fleet_edges(ai_settings, aliens):
       """
          有外星人到达边缘时采取相应的措施
      """
       for alien in aliens.sprites():
           if alien.check_edges():
               change_fleet_direction(ai_settings, aliens)
               break


def change_fleet_direction(ai_settings, aliens):
   """
      将整全外星人下移并改变它们的方向
  """
   for alien in aliens.sprites():
       alien.rect.y += ai_settings.fleet_drop_speed
   ai_settings.fleet_direction *= -1


def check_aliens_bottom(ai_settings, game_stats, scoreb, screen, ship, aliens, bullets):
   """检测外星人是否到达屏幕底部"""
   screen_rect = screen.get_rect()
   for alien in aliens.sprites():
       if alien.rect.bottom >= screen_rect.bottom:
           # 外星人触底爆炸声
           music.voice_large()
           # 有外星人到达屏幕后进行像飞船被撞后一样的操作
           ship_aliens_hit(ai_settings, game_stats, scoreb, screen, ship, aliens, bullets)
           break


def ship_aliens_hit(ai_settings, game_stats, scoreb, screen, ship, aliens, bullets):
   """
      响应外星人飞船相撞的后续操作
  """
   # 外星人飞船相撞时 发出碰撞声音 ship_left减1
   if game_stats.ships_left > 0:
       music.voice_large()
       game_stats.ships_left -= 1

       # 更新屏幕上飞船的艘数
       scoreb.prep_ships()

   else:
       game_stats.game_active = False
       ai_settings.increase_wen()      # 游戏结束后alien的速度得回到最初为
       pygame.mouse.set_visible(True)  # 游戏结束后Play按钮显示出来

   # 清空外星人列表和子弹列表
   aliens.empty()
   bullets.empty()

   # 创建一群新的外星人并将飞船重新出现在屏幕在底部中央
   create_fleet(ai_settings, screen, ship, aliens)
   ship.center_ship()

   # 暂停让用户反应一会
   sleep(0.5)


def update_aliens(ai_settings, game_stats, scoreb, screen, ship, aliens, bullets):
   """
      更新外星人群中所有外星人的位置
  """
   check_fleet_edges(ai_settings, aliens)
   aliens.update()

   if pygame.sprite.spritecollideany(ship, aliens):
       """
      接收俩个实参--检测飞船和外星人是否发生碰撞:发生了---往下走;没发生---返回None
      """
       ship_aliens_hit(ai_settings, game_stats, scoreb, screen, ship, aliens, bullets)

   # 检测是否有外星人到达屏幕底部
   check_aliens_bottom(ai_settings, game_stats, scoreb, screen, ship, aliens, bullets)


def check_high_score(game_stats, scoreb):
   """检查是否诞生了新的最高得分"""
   if game_stats.score > game_stats.high_score:
       game_stats.high_score = game_stats.score
       scoreb.prep_high_score()
       
复制

3.alien.py(外星人)

# coding: UTF-8
# 创建外星人Alien类
import pygame
from pygame.sprite import Sprite


class Alien(Sprite):
   """
      表示单个外星人的类
  """
   def __init__(self, ai_sttings, screen):
       super(Alien, self).__init__()
       self.screen = screen
       self.ai_settings = ai_sttings

       # 加载外星人的图片并设置其rect属性
       self.image = pygame.image.load('images/alien.bmp')
       self.rect = self.image.get_rect()

       # 设置外星人之间的间隔
       self.rect.x = self.rect.width    # 将外星人左边距设置为外星人的宽度
       self.rect.y = self.rect.height    # 将上边距设置为外星人的高度

       # 存储外星人的准确位置
       self.x = float(self.rect.x)

   def check_edges(self):
       """
          如果外星人位于屏幕边缘就返回True
      """
       screen_rect = self.screen.get_rect()
       if self.rect.right >= screen_rect.right:  # 外星人元素右边将要越过屏幕右边时的状态---此时处于触及屏幕右边缘
           return True
       elif self.rect.left <= 0:     # 外星人元素左边<= 0时代表将要越过屏幕左边---此时处于触及屏幕的左边缘
           return True

   def update(self):
       """
          向左或向右移动外星人
      """
       self.x += (self.ai_settings.alien_speed_factor
                  * self.ai_settings.fleet_direction)  # 速度 * 移动方向
       self.rect.x = self.x

   def blitem(self):
       """
          在指定位置绘制外星人的位置
      """
       self.screen.blit(self.image, self.rect)
       
复制

4.ship.py(飞船)

# coding: UTF-8
# 创建飞船Ship类

import pygame
from pygame.sprite import Sprite


class Ship(Sprite):
   """
      初始化飞船并设置其初始位置
  """
   def __init__(self, ai_settings, screen):
       super().__init__()
       self.screen = screen
       self.ai_settings = ai_settings
       
       # 加载飞船图像并获取其外接矩形
       self.image = pygame.image.load('images/ship.bmp')
       self.rect = self.image.get_rect()     # 获取飞船图片外接矩形(即是让其可以像矩形一样被处理)
       self.screen_rect = self.screen.get_rect()        # 获取屏幕图片外接矩形(即是让其可以像矩形一样被处理)
       
       # 将每搜新飞船放在屏幕底部中央
       self.rect.centerx = self.screen_rect.centerx  # 将飞船的centerx与屏幕的centerx捆绑在一起
       self.rect.bottom = self.screen_rect.bottom     # 将飞船的bottom与屏幕的bottom捆绑在一起

       # 在飞船的属性center中存储小数值
       self.center = float(self.rect.centerx)

       # 飞船水平移动标志
       self.moving_right = False
       self.moving_left = False

   def update(self):
       """
          根据移动标志调整飞船水平位置
      """
       # 飞船持续向右移动
       if self.moving_right and self.rect.right < self.screen_rect.right:
           self.center += self.ai_settings.ship_speed_factor

       # 飞船持续向左移动
       if self.moving_left and self.rect.left > 0:
           self.center -= self.ai_settings.ship_speed_factor

       # 根据self.center更新image_rect对象
       self.rect.centerx = self.center
       
   def blitem(self):
       """
          在指定位置绘制飞船
      """
       self.screen.blit(self.image, self.rect)

   def center_ship(self):
       """让飞船在屏幕底部居中"""
       self.ship_center = self.screen_rect.centerx
复制

5.bullet.py(子弹)

# coding: UTF-8
# 创建子弹Bullet类

import pygame
from pygame.sprite import Sprite


class Bullet(Sprite):
   """
      一个对飞船发射的子弹进行管理的类
  """
   def __init__(self, ai_settings, screen, ship):
       """
          在飞船所处的位置创建一个子弹对象
      """
       super(Bullet, self).__init__()  # 继承Sprite
       self.screen = screen

       # 在(0, 0)位置上创建一个表示子弹的矩形,并设置其位置
       self.rect = pygame.Rect(0, 0, ai_settings.bullet_width, ai_settings.bullet_height)
       self.rect.centerx = ship.rect.centerx    # 将子弹的centerx设置为飞船的centerx
       self.rect.top = ship.rect.top            # 将子弹的top属性设置为飞船的top属性 让子弹看起来是从飞船中射出的

       # 将子弹的垂直位置用小数表示,方便调节速度
       self.y = float(self.rect.y)

       # 获取子弹其他属性
       self.bullet_color = ai_settings.bullet_color
       self.bullet_speed_factor = ai_settings.bullet_speed_factor

   def update(self):
       """
          向上移动子弹
      """
       # 更新表示子弹位置的小数值
       self.y -= self.bullet_speed_factor

       # 更新表示子弹的rect的位置
       self.rect.y = self.y

   def draw_bullet(self):
       """
          在屏幕上绘制子弹
      """
       pygame.draw.rect(self.screen, self.bullet_color, self.rect)  # 顺序为1 2 3 :2填充3,出现在1屏幕上
复制

6.button.py(play按钮)

# coding: UTF-8
# 创建开启游戏的play按钮

import pygame.font


class Button():
   """初始化按钮的属性"""
   def __init__(self, ai_settings, screen, msg):
       self.screen = screen
       self.screen_rect = screen.get_rect()

       # 设置按钮的尺寸和其他属性
       self.width, self.height = 200, 50
       self.button_color = (0, 208, 0)     # 按钮框的颜色--和外星人一样的颜色
       self.text_color = (255, 0, 0)   # 文本颜色--红色
       self.font = pygame.font.SysFont(None, 48)   # 使用默认字体,字号为48

       # 设置按钮的rect并使其居中
       self.button_rect = pygame.Rect(0, 0, self.width, self.height)
       self.button_rect.center = self.screen_rect.center

       # 按钮的标签只需要创建一次
       self.prep_msg(msg)

   def prep_msg(self, msg):
       """
          将文本渲染成图像并使其在按钮上居中
      """
       self.msg_image = self.font.render(msg, True, self.text_color)    # 将存储在msg中的文本转换成图像
       self.msg_image_rect = self.msg_image.get_rect()
       self.msg_image_rect.center = self.button_rect.center

   def draw_button(self):
       """绘制一个用颜色填充的按钮,然后绘制文本"""
       self.screen.fill(self.button_color, self.button_rect)
       self.screen.blit(self.msg_image, self.msg_image_rect)
       
复制

7.settings.py(游戏属性设置)

# coding: UTF-8
# 创建Settings设置类---功能对应的设置


class Settings():
   """
      《外星人入侵》的所有设置的类
  """
   def __init__(self):
       """
          初始化游戏的静态设置
      """
       # 屏幕宽度和高度、背景颜色设置
       self.screen_width = 1200
       self.screen_height = 800
       self.bg_color = (230, 230, 230)

       # 飞船数量的设置
       self.ship_limit = 3

       # 子弹设置
       self.bullet_width = 3
       self.bullet_height = 10
       self.bullet_color = 255, 0, 0

       # 设置屏幕上可同时出现的子弹数
       self.bullet_allowed = 8

       # 外星人设置
       self.fleet_drop_speed = 10

       # 加快游戏的节奏的速度
       self.speedup_scale = 1.1

       # 提高外星人得分节奏
       self.score_scale = 1.5

       self.initialize_dynamic_settings()

   def initialize_dynamic_settings(self):
       """初始化随游戏进行而变化的动态设置"""

       # 飞船移动速度
       self.ship_speed_factor = 2.5

       # 子弹移动速度
       self.bullet_speed_factor = 2

       # 外星人移动速度
       self.alien_speed_factor = 1

       # 每个外星人初始得分点
       self.alien_points = 50

       # fleet_direction为1表示向右移动 为-1表示向左移动
       self.fleet_direction = 1

   def increase_wen(self):
       """返回最初速度"""
       self.alien_speed_factor = 1
       # print("游戏重新开始后的初始速度:" + str(self.alien_speed_factor))

   def increase_speed(self):
       """逐渐提高速度设置"""
       self.ship_speed_factor *= self.speedup_scale
       self.bullet_speed_factor *= self.speedup_scale
       self.alien_speed_factor *= self.speedup_scale
       # print("游戏过程中依次累加的速度:" + str(self.alien_speed_factor) + "\n")

       # 逐渐提高外星人单次得分
       self.alien_points = int(self.alien_points * self.score_scale)
       # print(self.alien_points)
复制

8.scoreboard.py(分数)

# # coding: UTF-8
# # 创建得分Score类

import pygame
from pygame.sprite import Group
from ship import Ship


class Scoreboard():
   """显示得分信息的类"""
   def __init__(self, ai_settings, screen, game_stats):
       """初始化显示得分涉及的属性"""
       self.screen = screen
       self.screen_rect = screen.get_rect()
       self.ai_settings = ai_settings
       self.game_stats = game_stats

       # 显示得分信息时使用的字体设置
       self.text_color = (30, 30, 30)
       self.font = pygame.font.SysFont(None, 48)
       self.prep_images()

   def prep_images(self):
       """准备包含 最高得分、当前得分、游戏等级、飞船 的图像"""
       # 当前得分图像
       self.prep_score()

       # 最高得分图像
       self.prep_high_score()

       # 等级图像
       self.prep_level()

       # 飞船组图像
       self.prep_ships()

   def prep_score(self):
       """将当前得分转换为一幅渲染的图像"""
       round_score = round(self.game_stats.score, -1)  # 使得分为10的倍数 -1----10的倍数   -2--100的倍数 -3--1000的倍数
       score_str = "score:" + "{:,}".format(round_score)
       self.score_image = self.font.render(score_str, True, self.text_color,
                                               self.ai_settings.bg_color)

       # 将当前得分放在屏幕右上角
       self.score_image_rect = self.score_image.get_rect()
       self.score_image_rect.right = self.screen_rect.right - 20
       self.score_image_rect.top = 20

   def prep_high_score(self):
       """将最高得分转换为一幅渲染的图像"""
       high_round_score = round(self.game_stats.high_score, -1)  # 使得分为10的倍数 -1----10的倍数   -2--100的倍数 -3--1000的倍数
       high_score_str = "Mscore:" + "{:,}".format(high_round_score)
       self.high_score_image = self.font.render(high_score_str, True, self.text_color,
                                           self.ai_settings.bg_color)

       # 将最高得分放在顶部屏幕中央
       self.high_score_image_rect = self.high_score_image.get_rect()
       self.high_score_image_rect.centerx = self.screen_rect.centerx
       self.high_score_image_rect.top = self.score_image_rect.top

   def prep_level(self):
       """将等级转换为一幅渲染的图像"""

       self.level_image = self.font.render(("lev:" + str(self.game_stats.level)), True,
                                           self.text_color, self.ai_settings.bg_color)

       # 将等级放在等分下面
       self.level_image_rect = self.level_image.get_rect()
       self.level_image_rect.right = self.score_image_rect.right
       self.level_image_rect.top = self.score_image_rect.bottom + 10

   def prep_ships(self):
       """显示还剩下多少艘飞船"""
       self.ships = Group()
       for ship_number in range(self.game_stats.ships_left):
           ship = Ship(self.ai_settings, self.screen)
           ship.rect.x = 10 + ship_number * ship.rect.width
           ship.rect.top = 10
           self.ships.add(ship)

   def show_score(self):
       """在屏幕上显示当前得分和最高得分"""
       self.screen.blit(self.score_image, self.score_image_rect)
       self.screen.blit(self.high_score_image, self.high_score_image_rect)
       self.screen.blit(self.level_image, self.level_image_rect)
       # 绘制飞船
       self.ships.draw(self.screen)
       
复制

9.game_stats.py(游戏状态)

# coding: UTF-8
# 创建跟踪游戏统计信息的Game_Stats类

import json


class Game_Stats():
   """跟踪游戏统计信息的类"""
   def __init__(self, ai_settings):
       self.ai_settings = ai_settings
       self.reset_stats()
       # 游戏刚启动时处于活动状态
       self.game_active = False

       # 在任何情况情况下都不应重置最高得分,加载历史最高分
       self.high_score = 0
       with open('Max_score.json', encoding='UTF-8') as file:
           self.high_score = json.load(file)

   def reset_stats(self):
       """初始化在游戏运行期间可能变化的统计信息"""
       self.ships_left = self.ai_settings.ship_limit
       self.score = 0  # 每次有新的分数都应该重置
       self.level = 1  # 设置游戏等级
复制

10.music.py(音效)

# coding: UTF-8
# 关于游戏中各种声音效果的模块

import pygame


def voice_large():
   # 外星人到达了屏幕底部或者撞到飞船的大爆炸声
   explosion_large = pygame.mixer.Sound("musics/Explo_Large.wav")
   explosion_large.play()


def voice_small():
   # 增加子弹和外星人碰撞的小爆炸声
   explosion_small = pygame.mixer.Sound("musics/Explo_Small.wav")
   explosion_small.play()


def bullet_biu():
   # 增加子弹射出的biu声
   bullet_whiz = pygame.mixer.Sound("musics/Bullet_biu.wav")
   bullet_whiz.play()


def bg_music():
   # 游戏背景音乐(若游戏开始就一直播放)
   pygame.mixer.music.load("musics/order_music.mp3")
   
复制

11.游戏图片/音效素材获取

(1)链接:https://pan.baidu.com/s/1A4VS59igzuEQi1JoDBabnA

         提取码:8lp3 (包括图片以及音效)

(2)另外如果读者想换音效 可进下面链接进行寻找  

      链接:https://www.aigei.com/music(我也是从这扒的)

12.针对游戏过程中各种报错解决办法思路的提醒

(1)最关键的一点:要抓住最终报错语句 那句==很很很关键== 根据这句能够快速定位报错位置以及原因(2)学会百度筛选有效解决办法----==这个能力至关重要==(3)找文件中逻辑错误或书写前后不统一的错误---这个是大部分人会犯的错误的 ==你以为是那样的 实际不是那样的==

13.游戏完成阶段总结

从开始动手编写到游戏功能较完善的阶段 花了2周 我现阶段还是大学生每天有课要上 每天抽时间学 python也是自学一步一步慢慢走过来的  这其中遇到的问题也是千奇百怪的 让人头大 (难怪民间有种说法--计算机是玄学!!!)但很庆幸的是每个当时看起来艰难不可理解的报错都被我ko了 这种感觉 经历过的就会大大的懂 我个人是很享受那个过程的 进展缓慢每天打怪但每天都有收获 如该游戏过程中出现几次无某某库的时候 用“进入cmd 用pip install 报错缺少的库名”办法基本能够解决 嘻嘻…好啦 接下来让游戏放在朋友电脑上也可以玩 即使在没有相应的pycharm/python的环境也可。

三、主.py文件转可执行.exe文件

1.安装pyinstaller:

win+r进入cmd界面→pip install pyinstaller→等待成功(pip list可检测是否安装pyinstaller)
复制

2.主.py文件转可执行.exe文件

(1)在cmd界面中进入游戏中所有.py文件同在的那个文件夹:

d:→cd Python-Projects\a book of py\Projects\Project1(alien_invasion) chapter 12-14\alien_invasion
复制

(2)打包主.py文件:

pyinstaller -F -w --add-data "musics/*.mp3;./musics" --add-data "musics/*.mav;./musics" alien_invasion.py
复制

几点说明:

i.*通配符,表示music文件夹里所有的mp3文件、所有的wav文件 要使用双引号
ii.windows系统要使用分号作为文件原本的路径和要存放的路径的分隔符,这一点和linux系统不一样,linux系统使用冒号
iii.要存放的路径 ./music表示最外层目录下的music目录
复制

参数解析:

pyinstaller  xxx.py   打包成一个需要依赖文件的exe
pyinstaller -F xxx.py  打包成一个单独的exe,但是会有黑窗口
pyinstaller -F  -w xxx.py 打包成一个单独的exe去且除黑窗口==(游戏中没有用多媒文件用这条命令)==
复制

3.转后事件处理

打包成功后 在alien_invasion文件夹在==新出现三个文件==---build文件夹、dist文件夹、alien_invasion.spec文件 :可执行.exe文件在dish文件夹中 双击运行它就可:最终出现游戏运行界面 play it 哈哈哈…看着蛮顺利的是不 其实不然各种报错后面详说

四、报错情况分析以及解决办法

1.双击alien_invasion.exe执行文件出现闪退

(1)闪退理由:打包的时候只打包了alien_invasion.py主文件 生成的alien_invasion.exe在dist文件夹 与游戏所依赖的其他.py不在同一个目录下 ==所以所以所以!==.exe文件在运行的时候找!不!到!相关的模块!故而不能执行!闪退(.exe在黄色箭头文件夹中 其他.py文件在红色框框所在文件夹中)

(2)解决办法:把.exe文件抬到所导入模块所在的文件夹内就可以了。当然也可以把导入的模块搬到.exe文件所在的文件夹下,同一个道理的。

2.双击alien_invasion.exe执行文件弹出“Faied to execute script ***”错误

(1)分析:出现这个错误的时候 一头的雾水 就是简单一句话 错误定位也无处下手  度娘上针对这个错误也是各种说法 (2)思路:为了看到具体报错情况  后面所性把打包新出现的三个文件删除 重回到打包步骤----还记得上面有个“参数解析”不   ==把命令中的-w去掉==

pyinstaller -F --add-data "musics/*.mp3;./musics" --add-data "musics/*.mav;./musics" alien_invasion.py
复制

这个时候再双击.exe可看到具体报错情况以及定位:

(3)看到没 说打不开音效文件 报错理由其实和报错情况1(1)是一样一样的 故解决办法也和报错情况1(2)一样一样的==(当然啦如果你解决了报错情况1的问题 原则上是不会出现情况2的错误的 ---因为你都移动到同一个目录下去啦)==

五、压缩.exe相关素材

终于!终于!终于!---要发给朋友玩啦(要记得把相关素材放进去哦 什么图片呀、音效呀等 使用说明是我自己为了朋友愉快的玩耍加进去哈)

这里我也把游戏放上来了哈  想试玩的朋友 可以下载玩玩链接:https://pan.baidu.com/s/1lu9RHKrxjyBC7vfxMALQZA 提取码:2qn0

ps:由于打包成.exe时自动默认把anaconda下无用的包或库也打包进去了 导致.exe文件过大 这个问题后期找时间倒腾倒腾 也会找时间会对游戏改进完善的  主要是时间…


文章转载自K记忆,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论