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

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

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

Живой запуск

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

Исходный код


let value = 0;
class Example extends Phaser.Scene
{
    constructor ()
    {
        super();
    }

    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('desyrelPink', 'assets/fonts/bitmap/desyrel-pink.png', 'assets/fonts/bitmap/desyrel-pink.xml');
    }

    create ()
    {
        this.dynamic1 = this.add.bitmapText(0, 0, 'desyrel', 'hello world', 8);

        this.tweens.add({
            targets: this.dynamic1,
            duration: 2000,
            fontSize: 128,
            ease: 'Sine.easeInOut',
            repeat: -1,
            yoyo: true
        });

        this.dynamic2 = this.add.bitmapText(0, 200, 'desyrelPink', 'hello world', 32);

        this.tweens.add({
            targets: this.dynamic2,
            duration: 2000,
            scaleX: 6,
            scaleY: 4,
            ease: 'Sine.easeInOut',
            repeat: -1,
            yoyo: true
        });
    }

    update ()
    {
        this.dynamic1.text = 'Value: ' + value.toFixed(2);
        this.dynamic2.text = 'Value: ' + value.toFixed(2);

        value += 0.01;
    }
}

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

const game = new Phaser.Game(config);

Загрузка растровых шрифтов

Перед использованием BitmapText необходимо загрузить файлы шрифта. Phaser требует два файла: изображение (PNG) с глифами и XML-файл с их описанием (координаты и размеры).

Загрузка происходит в методе preload сцены с помощью метода this.load.bitmapFont(). Первый аргумент — ключ (key), по которому вы будете обращаться к шрифту в коде. Второй и третий — пути к изображению и XML-файлу соответственно.

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

Создание и базовая анимация текста

Создать объект BitmapText можно в методе create с помощью this.add.bitmapText(). Метод принимает координаты X, Y, ключ шрифта, начальную строку и начальный размер шрифта.

this.dynamic1 = this.add.bitmapText(0, 0, 'desyrel', 'hello world', 8);

Для анимации свойств объекта, таких как fontSize, scaleX или scaleY, используется система твинов Phaser (this.tweens.add()). Твин позволяет плавно изменять значение свойства за указанное время (duration) с заданной функцией плавности (ease). Параметры repeat: -1 и yoyo: true заставляют анимацию повторяться бесконечно и проигрываться в обратном порядке.

this.tweens.add({
    targets: this.dynamic1,
    duration: 2000,
    fontSize: 128,
    ease: 'Sine.easeInOut',
    repeat: -1,
    yoyo: true
});

Динамическое обновление содержимого

Одно из ключевых преимуществ BitmapText — возможность менять отображаемую строку в реальном времени, что идеально для счетчиков. Это делается через прямое присваивание свойству .text.

В примере глобальная переменная value увеличивается каждому кадру в методе update(). Ее текущее значение (отформатированное до двух знаков) записывается в текст обоих объектов BitmapText.

update ()
{
    this.dynamic1.text = 'Value: ' + value.toFixed(2);
    this.dynamic2.text = 'Value: ' + value.toFixed(2);
    value += 0.01;
}

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

Масштабирование vs Изменение размера шрифта

Пример демонстрирует два разных подхода к увеличению текста.

Первый объект (dynamic1) анимирует свойство fontSize. Это изменяет исходный размер глифов, качество остается высоким.

fontSize: 128,

Второй объект (dynamic2) использует масштабирование через свойства scaleX и scaleY. Этот подход может быть полезен для более резких или нелинейных трансформаций, но при сильном увеличении может привести к пикселизации.

scaleX: 6,
scaleY: 4,

Выбор между ними зависит от желаемого визуального эффекта и производительности.

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

BitmapText в Phaser — мощный и производительный инструмент для работы с текстом в играх. Вы научились загружать шрифты, создавать текстовые объекты, анимировать их свойства с помощью твинов и динамически обновлять содержимое. Для экспериментов попробуйте: анимировать другие свойства, например alpha или angle; использовать разные функции плавности (ease) из Phaser; комбинировать обновление текста из игровой логики (очки, таймер) с несколькими независимыми анимациями.