文章流程
一、项目环境背景介绍
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文件过大 这个问题后期找时间倒腾倒腾 也会找时间会对游戏改进完善的 主要是时间…