Como gerar sprite sheets automaticamente para o seu jogo feito com Phaser JS
Escrito em 22 de junho de 2021 - 🕒 3 min. de leituraEm um de meus primeiros devlogs do jogo Super Ollie, eu expliquei como automatizar a geração de sprite sheets para o Phaser 3 usando Webpack, mas acho que seria mais útil se eu tivesse um script externo para fazer isso, para que qualquer pessoa pudesse usá-lo.
Mas porque não simplesmente usar um daqueles sites que combinam arquivos PNG
em um sprite sheet? Bem, porque o Phaser não precisa apenas do sprite sheet em PNG
, mas também de um arquivo atlas em JSON
com todos os detalhes do sprite sheet, como o nome do frame e as dimensões da imagem.
Para isso, vou usar o package free-tex-packer-core feito pelo odrick. O uso básico em sua documentação é o seguinte:
const { packAsync } = require('free-tex-packer-core');
const images = [
{ path: "img1.png", contents: fs.readFileSync("./img1.png") },
{ path: "img2.png", contents: fs.readFileSync("./img2.png") },
{ path: "img3.png", contents: fs.readFileSync("./img3.png") }
];
const options = { allowRotation: false };
async function packImages() {
try {
const files = await packAsync(images, options);
for (let item of files) {
console.log(item.name, item.buffer);
}
} catch (error) {
console.log(error);
}
}
Isso por si só já é super útil, mas eu quero melhorar isso e gerar sprite sheets para todos os meus sprites, e a estrutura como tenho meus arquivos e pastas é:
- original-files
- sprites
- hero
- hero_walking_1.png
- hero_walking_2.png
- hero_walking_3.png
- hero_jumping_1.png
- hero_jumping_2.png
- enemy
- enemy_walking_1.png
- enemy_walking_2.png
Com essa estrutura de diretórios, eu posso ter o seguinte script que percorrerá todos os diretórios no meu diretório de sprites e pegará as imagens dentro de cada um deles:
const { packAsync } = require('free-tex-packer-core');
const path = require('path');
const { readFileSync, readdirSync, writeFileSync } = require('fs');
const SOURCE_SPRITES_PATH = path.resolve(__dirname, 'original-files', 'sprites');
const SPRITES_PATH = path.resolve(__dirname, 'assets', 'sprites');
async function generateAtlasFiles(assetName) {
let spritesFolders;
// use the parameter or get all folders from a directory
if (assetName) {
spritesFolders = [assetName];
} else {
spritesFolders = readdirSync(SOURCE_SPRITES_PATH);
}
for (const spritesFolder of spritesFolders) {
const spritesFiles = readdirSync(path.resolve(__dirname, SOURCE_SPRITES_PATH, spritesFolder));
const images = [];
spritesFiles.forEach((spritesFile) => {
images.push({
path: spritesFile,
contents: readFileSync(
path.resolve(__dirname, SOURCE_SPRITES_PATH, spritesFolder, spritesFile)
),
});
});
await packImages(images, spritesFolder);
}
}
async function packImages(images, spriteName) {
try {
const files = await packAsync(images, { allowRotation: false });
// let's save the png and json files
for (const item of files) {
// get the file extension
const fileExt = item.name.split('.').at(-1);
// save the file in the sprites directory
await writeFileSync(
path.resolve(__dirname, SPRITES_PATH, `${spriteName}.${fileExt}`),
item.buffer
);
}
} catch (error) {
console.log(error);
}
}
// process.argv[2] is the argument from the command when you run `node script.js arg`
generateAtlasFiles(process.argv[2]);
Este script irá criar os arquivos my-sprite.png
e my-sprite.json
para cada um de seus sprites em sua pasta de sprites ao executar node generate-sprites.js
, ou node generate-sprites.js hero
para gerar sprites sheets para apenas um sprite, neste caso o sprite hero
.
Espero que esse post tenha sido útil para você, até a próxima.
Tags:
Posts relacionados
Publicar um comentário
Comentários
Nenhum comentário.