应用程序资源

本指南的前几节已经描述了如何使用pyglet加载图像、媒体和文本文档。应用程序通常还需要加载其他数据文件:例如,游戏中的级别描述、国际化字符串等。

例如,程序员经常想用::加载他们的应用程序所需的图像:

image = pyglet.image.load('logo.png')

此代码假定 logo.png 位于当前工作目录中。遗憾的是,工作目录不一定与包含应用程序脚本文件的目录相同。

  • 从命令行启动的应用程序可以从任意工作目录启动。

  • 捆绑到鸡蛋、Mac OS X包或Windows可执行文件中的应用程序的资源可能在ZIP文件中。

  • 应用程序可能需要更改工作目录才能使用用户的文件。

解决此问题的常见解决方法是构建相对于脚本文件的路径,而不是工作目录:

import os

script_dir = os.path.dirname(__file__)
path = os.path.join(script_dir, 'logo.png')
image = pyglet.image.load(path)

除了编写起来单调乏味之外,它仍然不适用于ZIP文件中的资源,并且在跨多个包的项目中可能会很麻烦。

这个 pyglet.resource 模块很好地解决了这个问题::

image = pyglet.resource.image('logo.png')

以下各节准确地描述了如何定位资源,以及如何定制行为。

正在加载资源

使用 pyglet.resource 模块,当需要加载应用程序附带的文件时。例如,不是写::

data_file = open('file.txt')

使用::

data_file = pyglet.resource.file('file.txt')

此外,还有一些方便的函数可用于加载适用于pyglet的媒体文件。下表显示了标准文件函数的等效资源函数。

pyglet.resource.texture() 用于加载独立纹理。这在将纹理用于3D模型或通常直接使用OpenGL时非常有用。

pyglet.resource.image() 针对加载类似精灵的图像进行了优化,这些图像可以调整其纹理坐标。资源模块尝试将小图像打包到较大的纹理地图集中(在中进行了说明 纹理存储箱和地图集 )以实现高效呈现(这就是为什么此函数的返回类型可以是 TextureRegion )。如果希望在同一图像的多个副本上具有不同的Achor点,还建议直接使用纹理贴图集类。这是因为当多次加载图像时,您实际上将获得 same 反对回击。您仍然可以使用资源模块来获取图像位置,下一节将对此进行介绍。

资源位置

某些资源文件按名称引用其他文件。例如,一个HTML文档可以包含 <img src="image.png" /> 元素。在这种情况下,您的应用程序需要找到 image.png 相对于原始的HTML文件。

使用 pyglet.resource.location() 想要拿到一个 Location 描述应用程序资源位置的对象。此位置可以是文件系统目录或ZIP文件中的目录。这个 Location 对象可以直接按名称打开文件,因此您的应用程序不需要区分这些情况。

在下面的示例中, thumbnails.txt 假定文件包含图像文件名列表(每行一个),然后假定图像文件位于与 thumbnails.txt 文件::

thumbnails_file = pyglet.resource.file('thumbnails.txt', 'rt')
thumbnails_location = pyglet.resource.location('thumbnails.txt')

for line in thumbnails_file:
    filename = line.strip()
    image_file = thumbnails_location.open(filename)
    image = pyglet.image.load(filename, file=image_file)
    # Do something with `image`...

此代码正确地忽略了可能出现在资源路径上其他位置的具有相同文件名的其他图像。

指定资源路径

默认情况下,仅搜索脚本主目录(包含 __main__ 模块)。您可以设置 pyglet.resource.path 添加到要按顺序搜索的位置列表中。此列表已编入索引,因此在修改它之后,您需要调用 pyglet.resource.reindex()

路径列表中的每一项都是相对于脚本主目录的路径,或者是前面带有“at”符号的Python模块的名称 (@ )。例如,如果您希望将所有资源打包在 res 目录::

pyglet.resource.path = ['res']
pyglet.resource.reindex()

路径上的项不是递归搜索的,因此如果资源目录本身有子目录,则需要显式指定这些目录::

pyglet.resource.path = ['res', 'res/images', 'res/sounds', 'res/fonts']
pyglet.resource.reindex()

即使操作系统使用不同的字符,资源路径中的条目也始终使用正斜杠字符作为路径分隔符。

指定模块名称可以轻松地将代码与其资源组合在一起。下面的示例使用包含假设的 gui.skins.default 有关资源:

pyglet.resource.path = ['@gui.skins.default', '.']
pyglet.resource.reindex()

多台装载机

A Loader 封装完整的资源路径和缓存。这使您的应用程序可以清楚地分离不同模块的资源加载。加载器是为给定的搜索路径构造的,并且公开了与全局 pyglet.resource 模块功能。

例如,如果一个模块需要加载它自己的图形,但又不想干扰应用程序的其余资源加载,它将创建自己的 Loader 具有本地搜索路径::

loader = pyglet.resource.Loader(['@' + __name__])
image = loader.image('logo.png')

这尤其适用于“插件”模块。

您还可以使用 Loader 实例加载相对于某个用户指定的文档目录的一组资源。以下示例为命令行上指定的目录创建加载器:

import sys
home = sys.argv[1]
loader = pyglet.resource.Loader(script_home=[home])

这是使用未与应用程序捆绑的绝对目录和资源的唯一方式 pyglet.resource

保存用户首选项和数据

由于可以通过多种方式分发Python应用程序,包括在ZIP文件中,因此在应用程序目录(或更糟糕的是工作目录)中保存用户首选项、高分列表等通常是不可行的。资源模块提供了帮助实现这一点的功能。

这个 pyglet.resource.get_settings_path() 函数返回适合写入配置相关数据的目录。使用的目录遵循操作系统的约定:

  • ~/.config/ApplicationName/ 在Linux上(取决于 XDG_CONFIG_HOME 环境变量)。

  • $HOME\Application Settings\ApplicationName 在Windows上

  • ~/Library/Application Support/ApplicationName 在Mac OS X上

这个 pyglet.resource.get_data_path() 函数返回适合写入任意数据的目录,如保存文件。使用的目录遵循操作系统的约定:

  • ~/.local/share/ApplicationName/ 在Linux上(取决于 XDG_DATA_HOME 环境变量)。

  • $HOME\Application Settings\ApplicationName 在Windows上

  • ~/Library/Application Support/ApplicationName 在Mac OS X上

返回的目录名并不一定存在--创建它们是应用程序的责任。下面的示例在data目录中打开一个名为“SuperGame”的游戏的高分列表文件:

import os

dir = pyglet.resource.get_data_path('SuperGame')
if not os.path.exists(dir):
    os.makedirs(dir)
filename = os.path.join(dir, 'highscores.txt')
file = open(filename, 'wt')