使用PyInstaller捆绑游戏#

../../_images/floppy-disk.svg

您已经使用Arcade编写了您的游戏,它是一部杰作!恭喜你!现在你想和其他人分享它。这通常意味着帮助人们安装Python,下载必要的模块,复制您的代码,然后让它们都正常工作。分享并不是一件容易的事情。井, PyInstaller 可以改变这一切!

PyInstaller 是一种用于Python的工具,它允许您将整个Python应用程序捆绑成一个可以轻松共享的单文件可执行捆绑包。谢天谢地,它在Arcade上工作得很好!

我们将演示Windows的用法,但在Windows、Mac和Linux上,一切都应该完全相同。请注意,您只能为您所在的系统构建。这意味着,为了构建Windows版本,您必须在Windows机器上运行,对于Linux和Mac也是如此。

捆绑一个简单的Arcade脚本#

../../_images/script.svg

为了演示PyInstaller的工作原理,我们将:

  • 安装PyInstaller

  • 创建一个使用Arcade的简单示例应用程序

  • 将应用程序捆绑到一个文件的可执行文件中

  • 运行应用程序

首先,确保在您的Python环境中安装了Arcade和PyInstaller,并具有:

pip install arcade pyinstaller

那我们就需要我们的比赛。在这种情况下,我们将从简单开始。我们需要一个一个文件的游戏,不需要任何额外的图像或声音。一旦我们让它发挥作用,我们就可以变得更加复杂。创建名为的文件 main.py 其中包含以下内容:

示例游戏--main.py#
import arcade

arcade.open_window(400, 400, "My Game")

self.clear()
arcade.draw_circle_filled(200, 200, 100, arcade.color.BLUE)
arcade.finish_render()

arcade.run()

现在,通过从命令行运行PyInstaller来创建一个文件可执行捆绑包文件:

pyinstaller main.py --onefile

PyInstaller生成作为游戏捆绑包的可执行文件。它把它放在 dist\ 文件夹位于当前工作目录下。查找名为的文件 main.exe 在……里面 dist\ 。运行此命令并查看示例应用程序启动!

您可以将此文件复制到计算机上的任何位置并运行它。或者,与其他人分享。您的脚本所需的一切都在这个可执行文件中。

对于简单的游戏,这就是你需要知道的全部!但是,如果您的游戏从磁盘加载任何类型的数据文件,请继续阅读。

处理数据文件#

../../_images/data-files.svg

在创建包时,PyInstaller首先检查您的项目,并自动识别项目所需的几乎所有内容(一个Python解释器、已安装的模块等)。但是,它不能自动确定您的游戏正在从磁盘加载哪些数据文件(图像、声音、地图)。因此,您必须显式地告诉PyInstaller有关这些文件以及它应该将它们放在包中的位置。这是使用PyInstaller的 --add-data 标志:

pyinstaller main.py --add-data "stripes.jpg;."

传递给 --add-data 是“源”文件或目录(例如: stripes.jpg )标识PyInstaller应该在捆绑包中包含什么。分号后面的项是“Destination”(例如:“.”),它指定相对于包的根应该将文件放在包中的什么位置。在上面的示例中, stripes.jpg 将图像复制到捆绑包的根目录(“.”)。

在指示PyInstaller将数据文件包含在包中之后,必须确保代码从正确的目录加载数据文件。当您共享您的游戏包时,您无法控制用户将从哪个目录运行您的包。只有一个文件的PyInstaller包在运行时被解压缩到一个随机的临时目录,然后从那里执行,这让情况变得复杂起来。本文档描述了一种简单的方法,它允许您的代码在PyInstaller捆绑包中运行时执行和加载文件,并且在未捆绑时也能够运行。

你需要做两件事。首先,下面的代码片段必须放在脚本的开头:

if getattr(sys, 'frozen', False) and hasattr(sys, '_MEIPASS'):
    os.chdir(sys._MEIPASS)

此代码段使用 sys.frozensys._MEIPASS ,这两个都是由PyInstaller设置的。这个 sys.frozen 设置指示代码是否从包运行(“冻结”)。如果代码被“冻结”,则工作目录将更改为包解压缩到的根目录 (sys._MEIPASS )。PyInstaller通常将其一个文件捆绑包解压缩到一个名为类似以下内容的目录中: C:\Users\user\AppData\Local\Temp\_MEI123456

其次,一旦上面的代码设置了当前工作目录,代码中的所有文件路径都可以是相对路径(例如: resources\images\stripes.jpg )而不是绝对路径(例如: C:\projects\mygame\resources\images\stripes.jpg )。如果您完成这两件事并将数据文件添加到包中,如下所示,您的代码将能够“正常”运行以及在捆绑包中运行。

下面是一些示例,它们展示了如何将数据文件包含在一个PyInstaller包中的一些常见模式。这些示例首先显示了一个代码片段,该代码片段演示了如何加载数据(相对路径名),然后是将数据文件复制到包中的PyInstaller命令。他们都认为 os.chdir() 正在使用上面列出的代码片段。

一个数据文件#

如果您只是在与脚本相同的目录中有一个数据文件,请使用如下所示的相对路径引用该数据文件:

sprite = arcade.Sprite("stripes.jpg")

然后,使用如下所示的PyInstaller命令将数据文件包含在捆绑的可执行文件中:

pyinstaller main.py --add-data "stripes.jpg;."
...or...
pyinstaller main.py --add-data "*.jpg;."

一个数据目录#

../../_images/document-icon.svg

如果您有一个数据文件目录(如 images ),则使用如下所示的相对路径引用数据目录:

sprite = arcade.Sprite("images/player.jpg")
sprite = arcade.Sprite("images/enemy.jpg")

然后,使用如下所示的PyInstaller命令将该目录包含在捆绑的可执行文件中:

pyinstaller main.py --add-data "images;images"

多个数据文件和目录#

您可以使用 --add-data 多次标记以将多个文件和目录添加到包中:

pyinstaller main.py --add-data "player.jpg;." --add-data "enemy.jpg;." --add-data "music;music"

一个目录,一应俱全#

尽管您可以使用单独的 --add-data 标志,建议您编写游戏,以便所有数据文件都位于一个根目录下,通常名为 resources 。您可以使用子目录来帮助组织所有内容。示例目录树如下所示::

project/
|--- main.py
|--- resources/
     |--- images/
     |    |--- enemy.jpg
     |    |--- player.jpg
     |--- sound/
     |    |--- game_over.wav
     |    |--- laser.wav
     |--- text/
          |--- names.txt

使用这种方法,可以很容易地将所有数据绑定到一个 --add-data 旗帜。您的代码将使用相对路径名来加载资源,如下所示:

sprite = arcade.Sprite("resources/images/player.jpg")
text = open("resources/text/names.txt").read()

并且,您可以将整个目录树包括到包中,如下所示:

pyinstaller main.py --add-data "resources;resources"

为了保持捆绑过程的简单性,有必要花点时间来计划如何布局和加载数据文件。

上述处理数据文件的技术只是一种方法。如果希望在处理数据文件时获得更好的控制和灵活性,请阅读 PyInstaller Run-Time Information 文档。

现在你知道如何安装PyInstaller,包括数据文件,并将你的游戏捆绑成一个可执行文件,你就有了捆绑游戏并与你的新粉丝分享它所需的东西!

故障排除#

../../_images/detective.svg

使用单文件夹捆绑包进行故障排除#

如果您在使捆绑包正常工作时遇到问题,暂时省略 --onefile 旗帜来自 pyinstaller 指挥部。这将把你的游戏捆绑成一个文件夹捆绑包,里面有一个可执行文件。这使您可以检查文件夹的内容,并确保所有文件都位于您期望的位置。由生成的一个文件包 --onefile 只是这个单文件夹捆绑包的自解压缩存档。

PyInstaller未捆绑所需的模块#

在大多数情况下,PyInstaller能够分析您的项目并自动确定将哪些模块放入包中。但是,如果PyInstaller碰巧错过了一个模块,您可以使用 --hidden-import MODULENAME 用于显式指示PyInstaller包括模块的标志。请参阅 PyInstaller documentation 了解更多详细信息。

额外细节#

  • 您会注意到,在运行 pyinstaller ,a .spec 文件将出现在您的目录中。该文件是由PyInstaller生成的,不需要保存或签入您的源代码资源库。

  • 由PyInstaller生成的可执行单文件捆绑包 --onefile FLAG的启动速度将慢于原始应用程序或单文件夹捆绑包。这是意料之中的,因为一个文件包最终只是一个压缩文件夹,所以每次运行包时,它们必须花时间解压缩自己。

  • 默认情况下,当PyInstaller创建捆绑的应用程序时,该应用程序会打开一个控制台窗口。您可以通过添加 --windowed 标志添加到 pyinstaller 指挥部。

  • 有关上述主题的更多详细信息,请参阅下面的PyInstaller文档。

  • 本教程使用的是PyInstaller 4.x。

PyInstaller文档#

PyInstaller是一种灵活的工具,可以处理各种不同的情况。欲进一步阅读,请参考以下链接,链接至PyInstaller官方文档和GitHub页面: