¡Perfecto! Aquí tienes el artículo formateado como una entrada de blog, manteniendo el texto y el código originales intactos, pero organizados visualmente para ser más claros.
🖼️ Carga Asíncrona de Texturas en Pixi.js (Usando Bundles y Manifest)
Prosiguiendo con nuestra integración de Pixi.js en React, vamos a ver un método de carga de texturas compatible.
📁 Paso 1: Organización de Recursos
Lo primero sería crear en la carpeta "public" una carpeta "assets". A dicha carpeta le crearé una carpeta llamada "textures", para tener la mejor organización posible.
Quedará por tanto la ruta "assets/textures/" como ruta para guardar/cargar este tipo de recursos.
Lo siguiente será pegar adentro de dicha carpeta todos nuestros archivos de texturas.
📝 Paso 2: Creación del manifest.json
Hecho esto podemos proceder a crear en "public" el archivo manifest.json, el cual vamos a aprovechar para declarar "bundles", es decir, una suerte de paquete de texturas, para poder cargarlas en serie.
Archivo: public/manifest.json
{
"bundles": [
{
"name": "texture-assets",
"assets": [
{
"alias": "board1_texture",
"src": "assets/textures/board1.png"
}
]
}
]
}
🔄 Paso 3: Inicialización Asíncrona en React
Para darle tiempo a la inicialización de React, Pixi.js y la posterior carga de assets (además de evitar una doble inicializacion), vamos a no solo establecer una condición para chequear si todo se ha inicializado correctamente antes de proceder, sino también vamos a hacer que la función de inicialización sea async (asincrónica).
El PinballGame.tsx quedaría así:
Archivo: PinballGame.tsx
import React, { useEffect, useRef } from 'react';
import * as PIXI from 'pixi.js';
import { GameHandler, assetsReadyPromise } from './GameHandler';
export default function PinballGame() {
const containerRef = useRef<HTMLDivElement>(null);
const appRef = useRef<PIXI.Application | null>(null);
const gameHandlerRef = useRef<GameHandler | null>(null);
useEffect(() => {
const initializeGame = async () => {
if (!containerRef.current) return;
if (appRef.current) return;
try {
await assetsReadyPromise;
const app = new PIXI.Application();
await app.init({
resizeTo: containerRef.current,
background: '#111111',
});
containerRef.current?.appendChild(app.canvas);
appRef.current = app;
const gameHandler = new GameHandler(app);
gameHandler.init();
gameHandlerRef.current = gameHandler;
} catch(error) {
console.error("Error Initializing:", error);
}
};
initializeGame();
return () => {
if (gameHandlerRef.current) {
gameHandlerRef.current.destroy();
gameHandlerRef.current = null;
}
if (appRef.current) {
appRef.current.destroy(true, { children: true, context: true });
appRef.current = null;
}
};
}, []);
return <div ref={containerRef} style={{ width: '100%', height: '100%' }} />;
}
📦 Paso 4: Creación del GameHandler
Una vez inicializado exitosamente, se instanciará el GameHandler, el cual asincrónicamente leerá el archivo manifest que habíamos creado, y cargará el bundle deseado.
Archivo: GameHandler.ts (o similar)
import * as PIXI from 'pixi.js';
const loadAssetsGlobally = async () => {
if ((PIXI.Assets.resolver as any).isInitialized) {
return;
}
await PIXI.Assets.init({ manifest: 'manifest.json' });
await PIXI.Assets.loadBundle('texture-assets');
};
export const assetsReadyPromise = loadAssetsGlobally();
export class GameHandler {
private app: PIXI.Application;
private updateFn: (ticker: PIXI.Ticker) => void;
constructor(appInstance: PIXI.Application) {
this.app = appInstance;
this.updateFn = this.update.bind(this);
}
public init() {
this.setupStage();
this.app.ticker.add(this.updateFn);
}
private setupStage() {
}
private update(ticker: PIXI.Ticker) {
}
public destroy() {
this.app.ticker.remove(this.updateFn);
}
}
📐 Paso 5: Ajuste de Estilos CSS
Con esto ya tenemos todo preparado. Sin embargo para que quede todo bien ajustado a la pantalla en cuanto a escalado y a convenientemente remover la posible scrollbar, debemos retocar el archivo index.css, seteando principalmente las propiedades height y overflow.
Archivo: index.css (Completo)
:root {
font-family: system-ui, Avenir, Helvetica, Arial, sans-serif;
line-height: 1.5;
font-weight: 400;
color-scheme: light dark;
color: rgba(255, 255, 255, 0.87);
background-color: #242424;
font-synthesis: none;
text-rendering: optimizeLegibility;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
height: 100%;
}
a {
font-weight: 500;
color: #646cff;
text-decoration: inherit;
}
a:hover {
color: #535bf2;
}
html, #root {
height: 100%;
margin: 0;
padding: 0;
overflow: hidden;
}
body {
margin: 0;
min-width: 320px;
min-height: 100vh;
height: 100%;
overflow: hidden;
}
h1 {
font-size: 3.2em;
line-height: 1.1;
}
button {
border-radius: 8px;
border: 1px solid transparent;
padding: 0.6em 1.2em;
font-size: 1em;
font-weight: 500;
font-family: inherit;
background-color: #1a1a1a;
cursor: pointer;
transition: border-color 0.25s;
}
button:hover {
border-color: #646cff;
}
button:focus,
button:focus-visible {
outline: 4px auto -webkit-focus-ring-color;
}
@media (prefers-color-scheme: light) {
:root {
color: #213547;
background-color: #ffffff;
}
a:hover {
color: #747bff;
}
button {
background-color: #f9f9f9;
}
}
Con esto el código es funcional. Ahora podemos proceder a la creación de Sprites, o incluso a agregar mas texturas a nuestro archivo manifest.json.

0 Comentarios