Pobtastic / Goldfish Game / Font

Created Sat, 20 Apr 2024 07:37:30 +0100 Modified Thu, 12 Dec 2024 14:35:47 +0000

Introduction

The first real “snag” I experienced with Phaser was how to use custom fonts.

You can only display fonts that are currently loaded and available to the browser: therefore fonts must be preloaded. Phaser does not do ths for you, so you will require the use of a 3rd party font loader, or have the fonts ready available in the CSS on the page in which your Phaser game resides.

Okay, that gives us a bunch of options - I went with, in my opinion, the simplest.

  document.addEventListener('DOMContentLoaded', function() {
    const font = new FontFace('ZXSpectrum', "url('/fonts/ZXSpectrum.ttf') format('truetype')");
    font.load().then(function(loadedFont) {
      document.fonts.add(loadedFont);

      .. Phaser code.

    }).catch(function(error) {
      console.error('Font failed to load:', error);
    });
  });
It’s maybe not that elegant, but it works great with a project I found on GitHub zx-spectrum-unicode-font.

Let’s try it out:

  document.addEventListener('DOMContentLoaded', function() {
    const font = new FontFace('ZXSpectrum', "url('/fonts/ZXSpectrum.ttf') format('truetype')");
    font.load().then(function(loadedFont) {
      document.fonts.add(loadedFont);

      class BaseScene extends Phaser.Scene {

        constructor(key) {
          super({ key: key });

          // Simply because I've made the assets use scale 4 in the disassembly.
          this.gameScale = 4;

          // Storage for any text which might need altering (e.g. number of
          // fish caught).
          this.textObjects = {};
        }

        printAt(text, x, y, fontSize = '32px', color = '#CDC6CD') {
          // Set up the text style:
          const textStyle = {
            fontFamily: 'ZXSpectrum',
            fontSize: fontSize,
            color: color
          };

          // Put the onus on the call to store the text object, if it's static
          // text - it can just "fire-and-forget".
          return this.add.text(
            8 * x * this.gameScale,
            8 * y * this.gameScale,
            text,
            textStyle
          );
        }

      }

      class SplashScreen extends BaseScene {

        constructor() {
          super('SplashScreen');
        }

        create() {
          // All static text:
          this.printAt("   BOOTY BY JOHN F CAIN   ", 2, 4);
          this.printAt("CATCH 20 GOLDFISH", 7, 12);
          this.printAt("BUT DONT RUN OUT OF AIR", 4, 14);
          this.printAt("OR GET TOO CLOSE TO THE BIG FISH", 0, 16);
        }

      }

      const config = {
        type: Phaser.AUTO,
        width: 1024,
        height: 768,
        scene: SplashScreen,
        backgroundColor: '#000000',
        physics: {
          default: 'arcade',
          arcade: {
            debug: false
          }
        },
        scale: {
          mode: Phaser.Scale.FIT,
          parent: 'gameContainer',
          autoCenter: Phaser.Scale.CENTER_BOTH,
          zoom: 0.5
        }
      };

     const game = new Phaser.Game(config);

    }).catch(function(error) {
      console.error('Font failed to load:', error);
    });
  });

For non-static text, the only one we have is for the number of collected fish. As it updates, we need to store a reference to it - this is simple though:

  // Note; we use a label on this text as it needs to be updated.
  this.textObjects['fish-count'] = this.printAt("0", 6, 22, "32px", "#000000");

And (sneak preview), the goldfish collection handler updates this text object directly:

  // Updates the fish caught counter on the screen. Note; when the count is
  // above 10, we move the horizontal position one digit left to keep the
  // unit aligned.
  this.textObjects['fish-count'].setText(this.data.get('fishCaught'));
  this.textObjects['fish-count'].setPosition((this.data.get('fishCaught') >= 10 ? 5 : 6) * 8 * this.gameScale, 22 * 8 * this.gameScale);

That looks spot on to me!

Booty Disassembly