文章流程
- 一、项目环境背景介绍
- 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版本
环境搭建的帖子(这位哥们写得很细的 点赞):
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 sysimport pygamefrom bullet import Bulletfrom alien import Alienfrom time import sleepimport jsonimport musicdef 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 = Falsedef 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_xdef 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_rowsdef 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) breakdef change_fleet_direction(ai_settings, aliens): """ 将整全外星人下移并改变它们的方向 """ for alien in aliens.sprites(): alien.rect.y += ai_settings.fleet_drop_speed ai_settings.fleet_direction *= -1def 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) breakdef 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 pygamefrom pygame.sprite import Spriteclass 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 pygamefrom pygame.sprite import Spriteclass 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 pygamefrom pygame.sprite import Spriteclass 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.fontclass 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 pygamefrom pygame.sprite import Groupfrom ship import Shipclass 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 jsonclass 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 pygamedef 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 打包成一个需要依赖文件的exepyinstaller -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文件过大 这个问题后期找时间倒腾倒腾 也会找时间会对游戏改进完善的 主要是时间…