О чем этот пример

Отображение текста — базовая задача для любой игры. Phaser предлагает мощную систему BitmapText, которая использует предварительно отрендеренные шрифты в виде текстур. Это решение идеально подходит для случаев, когда требуется стабильное и быстрое отображение текста, особенно динамически изменяющегося, без потери производительности. В этой статье мы разберем, как загружать и использовать bitmap-шрифты, создавать статические надписи и обновлять текст на лету, как в счетчиках очков или таймерах.

Версия Phaser: код и демо в этой статье рассчитаны на Phaser 3.90.0.

Живой запуск

Ниже встроен рабочий билд примера. Оригинальный источник: GitHub.

Исходный код


class Example extends Phaser.Scene
{
    dynamic = null;
    value = 0;

    preload ()
    {
        this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
        this.load.bitmapFont('desyrel', 'assets/fonts/bitmap/desyrel.png', 'assets/fonts/bitmap/desyrel.xml');
        this.load.bitmapFont('desyrel-pink', 'assets/fonts/bitmap/desyrel-pink.png', 'assets/fonts/bitmap/desyrel-pink.xml');
        this.load.bitmapFont('shortStack', 'assets/fonts/bitmap/shortStack.png', 'assets/fonts/bitmap/shortStack.xml');
    }

    create ()
    {
        this.add.bitmapText(0, 0, 'desyrel', 'Lorem ipsum\ndolor sit amet');
        this.add.bitmapText(0, 200, 'desyrel-pink', 'Excepteur sint occaecat\ncupidatat non proident');
        this.add.bitmapText(0, 400, 'shortStack', 'Phaser BitmapText');

        this.dynamic = this.add.bitmapText(0, 500, 'desyrel', '');
    }

    update ()
    {
        this.dynamic.text = `value: ${this.value.toFixed(2)}`;
        this.value += 0.01;
    }
}

const config = {
    type: Phaser.AUTO,
    parent: 'phaser-example',
    scene: Example
};

const game = new Phaser.Game(config);

Загрузка bitmap-шрифтов в preload

Перед использованием bitmap-шрифт необходимо загрузить. Метод this.load.bitmapFont() принимает три ключевых аргумента: ключ для последующего обращения, путь к файлу текстуры (изображение с глифами) и путь к файлу дескриптора (обычно в формате XML или JSON), который описывает расположение каждого символа на текстуре.

this.load.bitmapFont('desyrel', 'assets/fonts/bitmap/desyrel.png', 'assets/fonts/bitmap/desyrel.xml');

В примере загружаются три разных шрифта под разными ключами. Установка базового URL через this.load.setBaseURL() позволяет указывать только относительные пути для ресурсов, что делает код чище.

Создание статического текста

После загрузки шрифты готовы к использованию в методе create(). Создать объект bitmap-текста можно с помощью this.add.bitmapText(). Этот метод принимает начальные координаты (x, y), ключ загруженного шрифта и строку для отображения.

this.add.bitmapText(0, 0, 'desyrel', 'Lorem ipsum\ndolor sit amet');
this.add.bitmapText(0, 200, 'desyrel-pink', 'Excepteur sint occaecat\ncupidatat non proident');

Обратите внимание на использование символа \n для переноса строки. Каждый вызов создает независимый игровой объект, который можно далее перемещать, анимировать или изменять.

Динамическое обновление текста

Главное преимущество bitmap-шрифтов — эффективное обновление текста в реальном времени, что критично для счетчиков, времени или индикаторов здоровья. Для этого нужно сохранить ссылку на созданный объект BitmapText в переменную класса.

// В методе create()
this.dynamic = this.add.bitmapText(0, 500, 'desyrel', '');

Затем, в методе update(), который вызывается каждый кадр, мы можем менять свойство .text этого объекта. В примере отображается инкрементируемое числовое значение.

// В методе update()
this.dynamic.text = `value: ${this.value.toFixed(2)}`;
this.value += 0.01;

Изменение свойства .text приводит к мгновенному перестроению отображаемой текстуры из заранее загруженных глифов, что выполняется очень быстро.

Конфигурация игры и запуск сцены

Код примера завершается стандартной для Phaser конфигурацией и созданием экземпляра игры. В конфиге указывается тип рендерера (Phaser.AUTO), ID родительского HTML-элемента и класс основной сцены.

const config = {
    type: Phaser.AUTO,
    parent: 'phaser-example',
    scene: Example
};
const game = new Phaser.Game(config);

При создании игры автоматически инициируется жизненный цикл сцены: preload(), create(), а затем циклический вызов update().

Что попробовать дальше

Bitmap-шрифты в Phaser — это надежный инструмент для работы с текстом, сочетающий высокую производительность и гибкость. Они незаменимы для динамического контента в играх. Для экспериментов попробуйте: анимировать положение динамического текста, менять его оттенок через setTint, привязать обновление значения не к кадру, а к игровому событию (например, сбору монеты), или комбинировать несколько bitmap-текстов для создания сложных интерфейсов.