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

При создании динамических интерфейсов или анимированных текстовых элементов в играх на Phaser важно не только изменять визуальный масштаб объекта, но и понимать, как эти изменения влияют на его физические границы (bounds). Этот пример демонстрирует работу с масштабированием `BitmapText` и визуализацией его фактических размеров, что критически важно для точного позиционирования, обработки столкновений и создания плавных анимаций, взаимодействующих с другими игровыми объектами.

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

Живой запуск

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

Исходный код


class Example extends Phaser.Scene
{
    constructor ()
    {
        super();
    }

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

    create ()
    {
        this.string = 'Phaser 3\nBitmapText\nScaling\nwith bounds';

        this.text = this.add.bitmapText(0, 0, 'atari', this.string).setFontSize(32);

        this.graphics = this.add.graphics({ x: 0, y: 0, lineStyle: { thickness: 1, color: 0xffff00, alpha: 1 } });

        this.tweens.add({
            targets: this.text,
            duration: 4000,
            scaleX: 2,
            ease: 'Quad.easeInOut',
            repeat: -1,
            yoyo: true
        });

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

    update ()
    {
        this.text.setText(this.string + '\nScale X: ' + this.text.scaleX.toFixed(4));
        this.graphics.clear();
        this.graphics.strokeRect(this.text.x, this.text.y, this.text.width, this.text.height);
    }
}

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


const game = new Phaser.Game(config);

Загрузка bitmap-шрифта и создание текста

Перед использованием bitmap-шрифта его необходимо загрузить. Этот тип шрифтов состоит из изображения (спрайтшита) и файла описания (обычно XML), что позволяет рендерить текст быстро и без использования системных шрифтов.

В методе preload мы загружаем шрифт 'atari' с указанием путей к PNG и XML файлам. Базовый URL упрощает загрузку из удаленного репозитория.

В методе create создается сам текстовый объект. Ключевой момент — начальная позиция (0, 0) и установка размера шрифта через setFontSize(32). BitmapText использует целочисленные размеры для четкого отображения.

// Загрузка шрифта
this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
this.load.bitmapFont('atari', 'assets/fonts/bitmap/atari-smooth.png', 'assets/fonts/bitmap/atari-smooth.xml');

// Создание текстового объекта
this.string = 'Phaser 3\nBitmapText\nScaling\nwith bounds';
this.text = this.add.bitmapText(0, 0, 'atari', this.string).setFontSize(32);

Анимация масштабирования с помощью Tween

Для создания плавной анимации трансформаций в Phaser используется система Tweens. В примере создаются два независимых твина, которые управляют масштабировами объекта this.text по осям X и Y с разной длительностью и поведением.

Первый твин за 4 секунды увеличивает scaleX до 2, а затем возвращает к 1. Второй твин работает быстрее (2 секунды) и изменяет scaleY до 4. Параметр yoyo: true заставляет анимацию воспроизводиться в обратном порядке, а repeat: -1 делает ее бесконечной.

// Анимация масштаба по оси X
this.tweens.add({
    targets: this.text,
    duration: 4000,
    scaleX: 2,
    ease: 'Quad.easeInOut',
    repeat: -1,
    yoyo: true
});

// Анимация масштаба по оси Y
this.tweens.add({
    targets: this.text,
    duration: 2000,
    scaleY: 4,
    ease: 'Quad.easeInOut',
    repeat: -1,
    yoyo: true
});

Визуализация границ (Bounds) и обновление текста

Одна из ключевых особенностей примера — демонстрация того, как свойства width и height объекта BitmapText изменяются в реальном времени при масштабировании. Эти свойства возвращают текущие фактические размеры объекта с учетом масштаба, а не исходные размеры шрифта.

В методе update, который вызывается каждый кадр, происходит две важные вещи: 1. Обновляется содержимое текста, чтобы отображать текущее значение scaleX. 2. Перерисовывается желтый прямоугольник (Graphics), обводящий текущие границы текстового объекта.

update ()
{
    // Динамическое обновление текста с текущим масштабом
    this.text.setText(this.string + '\nScale X: ' + this.text.scaleX.toFixed(4));

    // Очистка предыдущей графики и отрисовка нового прямоугольника по границам
    this.graphics.clear();
    this.graphics.strokeRect(this.text.x, this.text.y, this.text.width, this.text.height);
}

Объект this.graphics создается в create() и служит для отладки, наглядно показывая, как меняется занимаемая объектом область.

Конфигурация игры и инициализация

Код завершается стандартной для Phaser 3 конфигурацией игры. Указывается тип рендерера, размеры холста, ID родительского HTML-элемента и класс основной сцены. После создания экземпляра Phaser.Game с этой конфигурацией игра запускается.

const config = {
    type: Phaser.AUTO, // Автовыбор между WebGL и Canvas
    width: 800,
    height: 600,
    parent: 'phaser-example', // ID контейнера в HTML
    scene: Example // Главная сцена
};

const game = new Phaser.Game(config);

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

Этот пример наглядно показывает, что свойства width и height игровых объектов в Phaser (в данном случае BitmapText) динамически пересчитываются при применении трансформаций, таких как масштабирование. Это фундаментально для точного позиционирования, расчета столкновений (this.physics.add.image) и создания сложных анимаций. Для экспериментов попробуйте

  1. Привязать анимацию масштаба к вводу игрока (например, клику)
  2. Добавить физическое тело к тексту и посмотреть, как width/height влияют на коллайдер
  3. Создать несколько масштабируемых текстовых объектов, которые взаимодействуют друг с другом через свои границы