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

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

Версия 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');
    }

    create ()
    {
        const text = this.add.text(100, 0, 'Phaser 3', { font: '32px Arial', fill: '#00ff00' });
        const text2 = this.add.text(100, -100, 'Phaser 3', { font: '32px Arial', fill: '#ffff00' });

        const matterText = this.matter.add.gameObject(text, { shape: { type: 'polygon', sides: 8, radius: 64 } }).setFrictionAir(0.001).setBounce(0.9);
        const matterText2 = this.matter.add.gameObject(text2).setFrictionAir(0.001).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() мы указываем базовый URL для загрузки ресурсов и загружаем одно изображение — спрайт платформы. Это изображение позже будет использоваться как статичное физическое тело.

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

Конфигурация игры определяет использование Matter.js в качестве физического движка. Обратите внимание на параметры: включен режим отладки debug: true (показывает контуры тел) и задана слабая гравитация по оси Y. Это ключевые настройки для нашей демонстрации.

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

Создание текстовых объектов

В методе create() создаются два текстовых объекта с помощью метода this.add.text(). Первый аргумент — позиция X, второй — Y. Третий аргумент — строка текста, а четвертый — объект стиля, определяющий шрифт и цвет заливки. Оба текста создаются с отрицательной или нулевой координатой Y, что помещает их за верхнюю границу экрана, откуда они начнут падать.

const text = this.add.text(100, 0, 'Phaser 3', { font: '32px Arial', fill: '#00ff00' });
const text2 = this.add.text(100, -100, 'Phaser 3', { font: '32px Arial', fill: '#ffff00' });

Превращение текста в физическое тело

Это самый важный шаг. Мы берем обычный объект текста (text) и передаем его в фабрику this.matter.add.gameObject(). Этот метод создает и возвращает Matter.js тело, связанное с игровым объектом.

Для первого текста мы задаем пользовательскую форму тела в виде многоугольника с 8 сторонами и радиусом 64 пикселя. Это создает более сложную и плавную форму для столкновений, чем стандартный прямоугольник (хитбокс) текста.

const matterText = this.matter.add.gameObject(text, { shape: { type: 'polygon', sides: 8, radius: 64 } }).setFrictionAir(0.001).setBounce(0.9);

Для второго текста мы не передаем параметры формы, поэтому Matter.js автоматически создаст тело на основе прямоугольного ограничивающего контейнера (bounding box) текстового объекта.

const matterText2 = this.matter.add.gameObject(text2).setFrictionAir(0.001).setBounce(0.9);

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

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

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

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

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

Как это работает в итоге

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

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

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

Связывание текста с физикой Matter.js — мощный и простой прием для добавления динамики в UI или создания нестандартных игровых объектов. Для экспериментов попробуйте: изменить форму тела на 'circle' или 'trapezoid'; применить разные физические материалы с помощью setFriction и setDensity; анимировать свойства самого текста (например, цвет или масштаб) во время физического взаимодействия; или сделать текст кинематическим телом, которым можно управлять с клавиатуры.