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

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

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

Живой запуск

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

Исходный код


class Example extends Phaser.Scene
{
    create ()
    {
        this.matter.world.setBounds().disableGravity();

        const arrow = '40 0 40 20 100 20 100 80 40 80 40 100 0 50';
        const chevron = '100 0 75 50 100 100 25 100 0 50 25 0';
        const star = '50 0 63 38 100 38 69 59 82 100 50 75 18 100 31 59 0 38 37 38';

        {
            const poly = this.add.polygon(400, 300, arrow, 0x0000ff, 0.2);

            this.matter.add.gameObject(poly, { shape: { type: 'fromVerts', verts: arrow, flagInternal: true } });

            poly.setVelocity(6, 3);
            poly.setAngularVelocity(0.01);
            poly.setBounce(1);
            poly.setFriction(0, 0, 0);
        }

        {
            const poly = this.add.polygon(400, 100, chevron, 0xff0000, 0.2);

            this.matter.add.gameObject(poly, { shape: { type: 'fromVerts', verts: chevron, flagInternal: true } });

            poly.setVelocity(6, 3);
            poly.setAngularVelocity(0.01);
            poly.setBounce(1);
            poly.setFriction(0, 0, 0);
        }

        {
            const poly = this.add.polygon(600, 400, star, 0x00ff00, 0.2);

            this.matter.add.gameObject(poly, { shape: { type: 'fromVerts', verts: star, flagInternal: true } });

            poly.setVelocity(4, -2);
            poly.setBounce(1);
            poly.setFriction(0, 0, 0);
            poly.setFrictionAir(0.005);
        }
    }
}

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

const game = new Phaser.Game(config);

Настройка сцены и физики

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

this.matter.world.setBounds().disableGravity();

Конфигурация игры указывает на использование Matter.js в качестве основного физического движка. Параметр debug: true включает отладочную визуализацию, которая рисует контуры физических тел — это крайне полезно при разработке.

Описание формы через вершины

Phaser позволяет описывать полигон через строку координат. Каждая пара чисел — это X и Y вершины относительно центра полигона. Такой формат удобен для задания сложных форм.

const arrow = '40 0 40 20 100 20 100 80 40 80 40 100 0 50';
const chevron = '100 0 75 50 100 100 25 100 0 50 25 0';
const star = '50 0 63 38 100 38 69 59 82 100 50 75 18 100 31 59 0 38 37 38';

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

Создание графического полигона

Сначала создаётся визуальный объект — полигон. Метод this.add.polygon() принимает координаты центра, строку с вершинами, цвет заливки и её альфа-канал (прозрачность).

const poly = this.add.polygon(400, 300, arrow, 0x0000ff, 0.2);

Это создаёт синюю полупрозрачную стрелку в центре экрана. На данном этапе это просто изображение без физических свойств.

Применение физического тела

Ключевой шаг — добавление к графическому объекту физического тела с помощью this.matter.add.gameObject(). В конфигурации указывается, что форма тела (shape) должна быть создана из вершин (type: 'fromVerts'). Параметр flagInternal: true помогает движку корректно обрабатывать вогнутые формы.

this.matter.add.gameObject(poly, { shape: { type: 'fromVerts', verts: arrow, flagInternal: true } });

После этого вызова объект poly становится полноценным телом Matter.js и наследует все его методы, такие как setVelocity или setBounce.

Настройка физических свойств

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

poly.setVelocity(6, 3);
poly.setAngularVelocity(0.01);
poly.setBounce(1);
poly.setFriction(0, 0, 0);

setBounce(1) делает отскок абсолютно упругим, а setFriction(0, 0, 0) убирает трение о поверхности и воздух. Для зелёной звезды дополнительно задано небольшое аэродинамическое сопротивление через setFrictionAir(0.005), что постепенно замедляет её.

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

Сочетание add.polygon и matter.add.gameObject позволяет легко создавать сложные интерактивные объекты с физикой. Для экспериментов попробуйте: изменить координаты вершин, чтобы создать собственную неправильную форму; комбинировать несколько полигонов в составное тело; использовать сенсоры (isSensor: true) для создания триггерных зон сложной формы; анимировать изменение вершин уже движущегося тела для эффекта трансформации.