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

Стандартные объекты вроде спрайтов легко превращаются в физические тела. Но что делать с текстом? В этом примере мы рассмотрим, как привязать полноценный физический движок Matter.js к объекту BitmapText. Это открывает путь к созданию интерактивных текстовых элементов, которые могут падать, отскакивать и сталкиваться, что идеально подходит для игровых меню, титров или разрушаемых интерфейсов. Мы разберем ключевой метод `this.matter.add.gameObject()`, который позволяет наделить физическими свойствами практически любой игровой объект, включая текст. Это мощный прием, расширяющий ваши возможности по созданию динамичных и визуально интересных сцен.

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

Живой запуск

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

Исходный код


class Example extends Phaser.Scene
{
    preload ()
    {
        this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
        this.load.image('platform', 'assets/sprites/platform.png');
        this.load.bitmapFont('desyrel', 'assets/fonts/bitmap/desyrel.png', 'assets/fonts/bitmap/desyrel.xml');
    }

    create ()
    {
        const text = this.add.bitmapText(140, -100, 'desyrel', 'Phaser 3');

        this.matter.add.gameObject(text, { render: { sprite: { yOffset: 0.2 } } });

        text.setFrictionAir(0.001);
        text.setBounce(0.9);

        this.matter.add.image(350, 450, 'platform', null, { isStatic: true }).setScale(2, 0.5).setAngle(10);
    }
}

const config = {
    type: Phaser.AUTO,
    width: 800,
    height: 600,
    backgroundColor: '#1b1464',
    parent: 'phaser-example',
    physics: {
        default: 'matter',
        matter: {
            debug: true,
            gravity: {
                y: 0.3
            }
        }
    },
    scene: Example
};

const game = new Phaser.Game(config);

Настройка сцены и загрузка ресурсов

В методе preload() мы загружаем два ресурса: изображение платформы и bitmap-шрифт. Обратите внимание на использование this.load.setBaseURL() для указания базового пути — это упрощает загрузку из удаленного репозитория.

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

Bitmap-шрифт загружается из двух файлов: изображения (.png) с набором символов и XML-файла (.xml), описывающего расположение каждого символа на этом изображении. Это классический формат для растровых шрифтов в играх.

Создание текста с физикой

В методе create() мы сначала создаем объект текста с помощью this.add.bitmapText(). Ключевая координата y: -100 размещает текст за верхней границей экрана, чтобы он упал вниз при старте сцены.

const text = this.add.bitmapText(140, -100, 'desyrel', 'Phaser 3');

Затем происходит самое важное: мы добавляем к этому текстовому объекту физическое тело движка Matter.js с помощью метода this.matter.add.gameObject(). Первым аргументом передается сам игровой объект (text), а вторым — конфигурация.

this.matter.add.gameObject(text, { render: { sprite: { yOffset: 0.2 } } });

Параметр render.sprite.yOffset смещает точку привязки (origin) физического тела относительно спрайта (или текста). Значение 0.2 немного опускает физическое тело вниз, что может помочь лучше выровнять визуальное и физическое представление для конкретного шрифта.

После этого текстовый объект text получает доступ ко всем методам физического тела. Мы настраиваем его свойства: очень низкое сопротивление воздуха (setFrictionAir(0.001)) для почти невесомого падения и высокий коэффициент упругости (setBounce(0.9)) для энергичных отскоков.

text.setFrictionAir(0.001);
text.setBounce(0.9);

Создание статической платформы

Чтобы текст не улетел в бездну, создадим для него препятствие — наклонную платформу. Мы используем this.matter.add.image(), который сразу создает и изображение, и привязанное к нему физическое тело.

this.matter.add.image(350, 450, 'platform', null, { isStatic: true }).setScale(2, 0.5).setAngle(10);

Ключевые моменты в этой строке: 1. Пятый аргумент — объект конфигурации тела. Флаг isStatic: true делает платформу неподвижной. На нее будут действовать столкновения, но гравитация и импульсы не смогут ее сдвинуть. 2. Метод .setScale(2, 0.5) растягивает изображение платформы по ширине (в 2 раза) и сжимает по высоте (в 0.5 раза). 3. Метод .setAngle(10) поворачивает платформу на 10 градусов, создавая наклонную поверхность для отскоков.

Теперь у падающего текста есть динамичная и непредсказуемая поверхность для взаимодействия.

Конфигурация Matter.js

Вся магия физики активируется в конфигурации игры. В блоке physics мы указываем движок matter как движок по умолчанию.

physics: {
    default: 'matter',
    matter: {
        debug: true,
        gravity: {
            y: 0.3
        }
    }
}

Настройки движка Matter.js: * debug: true — включает отладочную визуализацию. Вы увидите контуры физических тел (текста и платформы), что невероятно полезно для тонкой настройки столкновений и проверки размеров. * gravity: { y: 0.3 } — задает силу гравитации по оси Y. Значение 0.3 относительно слабое, что позволяет наблюдать за падением и отскоками в замедленном, более управляемом темпе.

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

Метод this.matter.add.gameObject() — это мост между визуальным представлением и физической симуляцией. Он позволяет быстро "оживить" такие объекты, как BitmapText, Container или TileSprite, наделяя их физическими свойствами. Для экспериментов попробуйте: 1. Заменить BitmapText на текстовый объект, созданный через this.add.text(), и посмотрите, как поведет себя физика с векторным шрифтом. 2. Создать несколько текстовых тел с разными словами и настроить между ними столкновения (setCollisionCategory, setCollidesWith). 3. Добавить интерактивность: сделать текст кликабельным и при клике применять к нему силу (applyForce) или импульс (setVelocity).