Pixi Asset Pack 1.0:资产管理的优化

521 阅读5分钟

令人兴奋的是,Pixi 的 Asset Pack 正式推出了 1.0 版本。我深入研究了一下,评估它是否可以为我们的项目带来好处。目前来看,它前景很好,但仍有一些问题需要解决。本文将介绍它的工作原理以及存在的问题。

首先,简单列出使用 Asset Pack 的理由:

  • 纹理精灵打包:不再需要手动使用 Texture Packer。
  • 自动压缩与文件格式:始终保持100%的原始资源,同时自动生成压缩的 PNG 和 WebP 版本。
  • 生成 Mipmaps:分辨率较低的设备可以使用低分辨率纹理以提升性能并减少游戏体积。
  • 生成 Bundle Manifest:不再需要手动编写资产列表。
  • 哈希版本控制:确保始终使用最新的文件。
  • 面向艺术家的工作流程:艺术家只需管理原始资源,导出自动化处理其余部分。

项目中的一些问题或限制:

  • Spine Atlas 导出问题:Spine atlas 未能正确导出(已提交 Pull Request 来解决 spine-runtime 的问题)。
  • Bitmap 字体导出问题:Bitmap 字体导出不正确(已提交Issue)。
  • Sound Sprite 支持:目前不支持(已提交Issue)。

如何打包

安装 Asset Pack 很简单,只需执行以下一行命令

npm install --save-dev @assetpack/core

然后创建一个 .assetpack.js 文件,如下:

import { pixiPipes } from '@assetpack/core/pixi';

export default {
	entry: './raw-assets',
	output: './public/assets',
	pipes: [
		...pixiPipes({
			resolutions: { high: 3, default: 2, low: 1 },
			manifest: {
				trimExtensions: true
			},
                        texturePacker: { texturePacker: { removeFileExtension: true }},
		}),
	],
};

pixiPipes 创建了一个默认的设置,适用于大多数情况。

  • resolutions:我们指定了三种分辨率,稍后会详细讨论。
  • manifest:trimExtensions:移除纹理文件的扩展名,这样可以用更简洁的代码引用它们。
  • texturePacker:texturePacker:removeFileExtension: 在打包纹理时,移除spritesheet Json中的纹理文件扩展名,方便引用。

现在,在项目根目录下创建一个名为 raw-assets 的文件夹,其中每个子文件夹都将成为一个 bundle,使用 {m}标签标记。根据您的项目结构,对我们项目来说,我创建了以下四个 bundle:

  • game-screen{m} :所有游戏资产,在加载屏幕显示后开始加载。
  • load-screen{m} :仅用于加载屏幕的所有资产,加载屏幕隐藏后卸载以节省内存。
  • shared{m} :加载屏幕和游戏中都使用的共享资产。
  • ui{m} :UI 资产,可以放在 game-screen 文件夹中,但单独分离以便于访问。

Asset Pack Raw Assets Structure

根据资产的类型,文件结构如下:

  • 单个精灵:只需将纹理放在任意文件路径中。使用文件名(不带扩展名)访问它,忽略文件夹路径,例如 background。如果您有两个相同文件名的文件(应避免这种情况),则需要使用相对路径访问它们,例如 shared/background

Asset Pack Single Sprite

  • 精灵表(Texture Packer) :将纹理放入带有 {tps} 标签的文件夹中,精灵表 JSON 文件将自动生成。使用文件夹名称访问纹理数组,例如 skins 将返回包含所有纹理文件名的数组。

Asset Pack Spritesheet

  • Spine:将 ATLAS、JSON 和纹理文件放入一个文件夹中。使用文件名(不带扩展名)访问 Spine 数据和 atlas 文件,例如 character-skel 和 character。如果 ATLAS 和 JSON 文件名相同(应避免),则需要通过文件扩展名访问它们,例如 character.json 和 character.atlas

Asset Pack Spritesheet

现在,运行 CLI 命令 npm assetpack,Asset Pack 将把所有资源打包到 public 文件夹中,并生成一个 manifest.json 文件,其中包含所有文件的引用。您还可以设置 GitHub workflow 来自动化此过程。

如何使用打包的资源

首先,看一下这段代码:

import { type AssetsManifest, Assets } from '@pixi/assets';
import type { Spritesheet } from '@pixi/spritesheet';
import * as utils from '@pixi/utils';
import { Sprite } from '@pixi/sprite';
import { Spine } from '@esotericsoftware/spine-pixi';

(async () => {
	const baseUrl = './public/assets';
	// const baseUrl = 'https://s3/my-bucket';

	const response = await fetch(baseUrl + '/manifest.json');
	const manifest = (await response.json()) as AssetsManifest;
	if (!manifest.bundles) {
		throw new Error('[Assets] Invalid assets manifest');
	}

	const resolution = Math.min(utils.isMobile.any ? window.devicePixelRatio : 3, 3);

	await Assets.init({
		basePath: baseUrl,
		manifest,
		texturePreference: { resolution: [resolution, 1], format: ['webp', 'png'] },
	});

	await Assets.loadBundle('shared');
	await Assets.loadBundle('load-screen');
	
	// load-screen 资源已加载,显示加载屏幕

	await Assets.loadBundle('ui');
	await Assets.loadBundle('game-screen', onProgress); // 使用 onProgress 更新进度条
	
	// 游戏资源已加载,等待玩家隐藏加载屏幕

	Assets.unloadBundle('load-screen');

	const singleSprite = Sprite.from('background');

	const spriteSheet = Assets.cache.get<Spritesheet>('skins');
	const spriteSheetSprite = new Sprite(spriteSheet.textures['hat.png']);

	const spine = Spine.from('character-skel', 'character');
})();

给定一个 baseUrl,我们可以在本地或服务器上加载资源。

我们将首选分辨率设置为 3x、2x 和 1x,并在移动设备上使用 devicePixelRatio,桌面设备则默认为 3x。您可以根据需求使用更多的分辨率值。

在 Assets.init() 中输入 manifest 文件、首选分辨率和格式。

使用 Assets.loadBundle() 加载资源包,Pixi 会根据 manifest 自动加载。

当加载屏幕完成后,可以使用 Assets.unloadBundle 卸载不再需要的资源包。

对于单个精灵,使用 Sprite.from() 加载精灵别名。

对于精灵表,首先需要通过 Assets.cache.get() 获取精灵表引用,然后使用精灵表中的纹理创建新的精灵对象。

对于 Spine 动画,使用 Spine.from() 加载骨架数据和 atlas 文件。

您始终可以从 manifest.json 文件中参考资源别名。

结论

虽然 Asset Pack 仍处于早期阶段,但我相信它有望成为 Pixi 开发中的重要工具。有人已经使用过它了吗?我很想听听大家的想法和经验!

(文中的代码参考并修改自知吾猪_6翻了版探索Pixi.js的潜力系列的文章)

(原英文文章 点击这里