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

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

Версия 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('block', 'assets/sprites/block.png');
        this.load.image('platform', 'assets/sprites/platform.png');
    }

    create ()
    {
        const Bodies = Phaser.Physics.Matter.Matter.Bodies;

        const rectA = Bodies.rectangle(0, 0, 200, 24);
        const rectB = Bodies.rectangle(0, 0, 24, 200);
        const circleA = Bodies.circle(-100, 0, 24);
        const circleB = Bodies.circle(100, 0, 24);
        const circleC = Bodies.circle(0, -100, 24);
        const circleD = Bodies.circle(0, 100, 24);

        const compoundBody = Phaser.Physics.Matter.Matter.Body.create({
            parts: [ rectA, rectB, circleA, circleB, circleC, circleD ]
        });

        const block = this.matter.add.image(150, 0, 'block');

        block.setExistingBody(compoundBody);

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

        //  A floor to land on
        this.matter.add.image(350, 450, 'platform', null, { isStatic: true }).setScale(2, 0.5).setAngle(8);
    }
}

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);

Что такое составное тело?

Составное тело (Compound Body) в Matter.js — это физический объект, созданный из двух или более простых тел (parts), которые жёстко связаны между собой. Они движутся, вращаются и сталкиваются как единое целое, но при этом форма коллизий соответствует совокупности всех частей.

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

Создание отдельных частей тела

Перед сборкой составного тела необходимо создать его части. В Matter.js для этого используются фабричные методы из пространства имён Phaser.Physics.Matter.Matter.Bodies. Координаты задаются относительно локального центра (точки вращения) будущего составного тела.

const Bodies = Phaser.Physics.Matter.Matter.Bodies;

const rectA = Bodies.rectangle(0, 0, 200, 24);
const rectB = Bodies.rectangle(0, 0, 24, 200);
const circleA = Bodies.circle(-100, 0, 24);
const circleB = Bodies.circle(100, 0, 24);
const circleC = Bodies.circle(0, -100, 24);
const circleD = Bodies.circle(0, 100, 24);

Здесь мы создаём: - rectA: горизонтальный прямоугольник шириной 200px и высотой 24px в центре (0,0). - rectB: вертикальный прямоугольник 24x200px, также в центре. - Четыре круга (circleA-circleD) радиусом 24px, смещённые на 100px от центра по осям X и Y. Обратите внимание, что координаты частей — локальные, они задают форму, а не позицию в мире.

Сборка составного тела

Когда все части готовы, их нужно объединить с помощью Phaser.Physics.Matter.Matter.Body.create. Ключевой параметр parts принимает массив ранее созданных тел. Порядок не имеет значения.

const compoundBody = Phaser.Physics.Matter.Matter.Body.create({
    parts: [ rectA, rectB, circleA, circleB, circleC, circleD ]
});

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

Связывание составного тела со спрайтом Phaser

В Phaser физическое тело должно быть связано с игровым объектом, например, с изображением (Image). Мы создаём спрайт, а затем привязываем к нему наше составное тело с помощью метода setExistingBody.

const block = this.matter.add.image(150, 0, 'block');
block.setExistingBody(compoundBody);

Важный момент: мы создаём изображение на позиции (150, 0) с текстурой 'block'. Однако физическая форма (compoundBody) была создана с локальными координатами частей относительно (0,0). Метод setExistingBody корректно применяет мировую позицию спрайта ко всему составному телу. Текстура 'block' будет растянута на область всего тела, что в данном примере визуально не оптимально, но демонстрирует принцип.

Настройка физических свойств и окружения

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

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

- setFrictionAir(0.001): Устанавливает очень низкое сопротивление воздуха, позволяя телу долго двигаться. - setBounce(0.9): Задаёт высокий коэффициент восстановления (отскок) — 0.9 (90%).

Затем создаётся статичная платформа (isStatic: true), на которую будет падать наше тело. Она масштабируется и немного поворачивается для наглядности.

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

Конфигурация физического движка Matter задаётся в config.physics.matter. Включён режим отладки (debug: true), который отрисовывает формы коллизий, и слабая гравитация по Y (y: 0.3).

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

Составные тела в Matter.js — мощный инструмент для моделирования объектов сложной геометрии без необходимости рисовать сложные полигональные формы коллизий вручную. Они идеально подходят для создания составных механизмов, разрушаемых объектов или персонажей с нестандартной физикой. Экспериментируйте: попробуйте создавать динамические составные тела (например, разрушаемые стены, которые распадаются на части), меняйте точки вращения составного тела методом setCentre, или создавайте «скелет» персонажа из кругов и прямоугольников, соединённых ограничителями (constraints).