Cargar tipografías en Phaser

Cómo precargar fuentes personalizadas


Phaser, al ser un framework Javascript que funciona sobre un navegador, puede cargar fuentes personalizadas muy facilmente, ayudándose de CSS. La regla @font-face de CSS nos permite indicar en unas pocas líneas la carga de una tipografía.

Sin embargo, existe un pequeño problema: el navegador puede tardar demasiado en descargarse las tipografías e iniciar el juego antes de que esten cargadas, mostrando una tipografía por defecto, y sólo con CSS no podemos gestionar ese problema.

En ecosistemas de Phaser, suelen recomendar utilizar la librería de terceros Webfontloader, que permite cargar las tipografías, y ejecutar una función cuando ya estén cargadas. Sin embargo, nosotros vamos a utilizar una aproximación nativa, en la que no necesitaremos librerías de terceros, sino que utilizaremos Javascript nativo directamente.

Cargar tipografías personalizadas

Para indicar a nuestro juego de Phaser que cargue una tipografía personalizada antes de iniciar el juego, vamos a crear un fontFamilies con la información de las tipografías que queremos cargar.

En nuestro ejemplo, cargaremos las tipografías EnterCommand y Pixellari, por lo que lo primero sería colocarlas en nuestra estructura de carpetas, concretamente en public/fonts/. He utilizado el formato .woff2, que tiene buen soporte.

const fontFamilies = [
  { name: "EnterCommand", url: "fonts/entercommand.woff2" },
  { name: "Pixellari", url: "fonts/pixellari.woff2" }
];

const loadFont = ({ name, url }) => {
  const font = new FontFace(name, `url(${url})`);
  return font.load().then((loadedFont) => {
    document.fonts.add(loadedFont);
    return loadedFont;
  });
};

await Promise.all(fontFamilies.map(loadFont));
const game = new Phaser.Game(config);

En el método loadFont, obtenemos un nombre y la URL de la tipografía y creamos una instancia con new FontFace(). Esto es el equivalente a lo que hacemos con CSS con la regla @font-face. Luego, llamamos al método load() para cargar la tipografía y añadirla a la lista de tipografías cargadas.

Es un poco más adelante, mediante el Promise.all(), donde realmente llamaremos a esa función loadFont() por cada una de nuestras tipografías definidas y, al tener un await pasará a continuar con las siguientes líneas de código, cuando se haya resuelto la promesa y las tipografías estén cargadas.

De esta forma, nunca llegaremos a crear el juego con el new Phaser.Game() hasta que las tipografías se encuentren cargadas.

Cargar tipografías con Webfontloader

Si por alguna razón, la estrategia anterior no te funciona o no puedes utilizarla, siempre puedes utilizar la librería de terceros Webfontloader, que hace algo muy similar, eso sí, necesitas instalarla:

$ npm install -D Webfontloader

Una vez instalada, la importamos y nos creamos una función loadFonts que se encargará de comprobar cuando las tipografías indicadas están cargadas en el navegador, y cuando esto ocurra, la promesa que devuelve se cumplirá:

import WebFont from "webfontloader";

const fontFamilies = ["EnterCommand", "Pixellari"];

const loadFonts = (families) =>
  new Promise((resolve, reject) => {
    WebFont.load({
      custom: { families },
      active: resolve,
      inactive: reject
    });
  });

await loadFonts(fontFamilies);
const game = new Phaser.Game(config);

El enfoque es muy similar al anterior, sin embargo, en este caso no se cargan las tipografías en el código Javascript, por lo que tenemos que añadir el código CSS con las reglas @font-face para que se carguen correctamente:

@font-face {
  font-family: EnterCommand;
  src:
    url("fonts/entercommand.woff2") format("woff2"),
    url("fonts/entercommand.woff") format("woff");
}

@font-face {
  font-family: Pixellari;
  src:
    url("fonts/pixellari.woff2") format("woff2"),
    url("fonts/pixellari.woff") format("woff");
}

Ahora sí, de la misma forma que antes, el await impedirá que se siga ejecutando el resto del código hasta que no estén las tipografías indicadas cargadas.

¿Quién soy yo?

Soy Manz, vivo en Tenerife (España) y soy streamer partner en Twitch y profesor. Me apasiona el universo de la programación web, el diseño y desarrollo web y la tecnología en general. Aunque soy full-stack, mi pasión es el front-end, la terminal y crear cosas divertidas y locas.

Puedes encontrar más sobre mi en Manz.dev