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

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

Версия 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('ball', 'assets/sprites/pangball.png');
    }

    create ()
    {
        this.matter.world.setBounds(0, 0, 800, 600, 32, true, true, false, true);

        //  Add in a stack of balls

        for (let i = 0; i < 64; i++)
        {
            const ball = this.matter.add.image(Phaser.Math.Between(100, 700), Phaser.Math.Between(-600, 0), 'ball');
            ball.setCircle();
            ball.setFriction(0.005);
            ball.setBounce(1);
        }
    }
}

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

const game = new Phaser.Game(config);

Настройка конфигурации Matter.js

Для использования Matter.js в проекте Phaser необходимо правильно настроить конфигурацию игры в объекте config. Ключевым моментом является указание physics.default и настройки в physics.matter.

const config = {
    type: Phaser.AUTO,
    width: 800,
    height: 600,
    backgroundColor: '#1d1d1d',
    parent: 'phaser-example',
    physics: {
        default: 'matter', // Активация Matter.js как физического движка по умолчанию
        matter: {
            enableSleeping: true // Включение оптимизации: неактивные тела "засыпают"
        }
    },
    scene: Example
};

Параметр enableSleeping: true позволяет движку переводить тела, которые остановились, в состояние "сна", что значительно снижает нагрузку на процессор в сценах со множеством статичных объектов.

Создание мира и его границ

В методе create() сцены происходит инициализация физического мира. Метод this.matter.world.setBounds() определяет его границы и их свойства.

create ()
{
    this.matter.world.setBounds(0, 0, 800, 600, 32, true, true, false, true);
}

Метод принимает координаты левого верхнего угла (x, y), ширину и высоту области. Последние четыре булевых параметра определяют, будут ли у границ (слева, сверху, справа, снизу) активны столкновения. В данном случае у правой границы (false) столкновения отключены, что может создавать эффект "стока" для объектов. Число 32 — это толщина невидимой границы.

Генерация и настройка физических тел

Далее в цикле создаются 64 спрайта с физическим телом. Каждому телу задаются физические свойства, превращающие картинку в динамический объект.

for (let i = 0; i < 64; i++)
{
    const ball = this.matter.add.image(Phaser.Math.Between(100, 700), Phaser.Math.Between(-600, 0), 'ball');
    ball.setCircle();
    ball.setFriction(0.005);
    ball.setBounce(1);
}

1. this.matter.add.image(): Создает спрайт из изображения 'ball' и сразу прикрепляет к нему твердое тело Matter.js. Начальные координаты `xзадаются случайно в пределах сцены, аy` — выше верхней границы (от -600 до 0), чтобы мячи падали сверху. 2. ball.setCircle(): Заменяет прямоугольную форму коллайдера тела на круглую, соответствующую спрайту мяча. Это критически важно для корректного и реалистичного отскока. 3. ball.setFriction(0.005): Устанавливает очень низкий коэффициент трения, почти как у льда. Мячи будут долго скользить и вращаться после столкновений. 4. ball.setBounce(1): Задает коэффициент упругости (реституции), равный 1. Это означает идеально упругие столкновения без потери энергии — мячи отскакивают от стен и друг друга, не теряя скорости.

Почему мячи ведут себя так реалистично?

Поведение, которое мы видим, — это результат работы движка Matter.js, который по умолчанию включает гравитацию (она направлена вниз, по оси Y). Мячи падают под действием этой гравитации, сталкиваются с границами мира и друг с другом согласно заданным свойствам: форме (setCircle), упругости (setBounce) и трению (setFriction).

Поскольку мячи спавнятся в случайных точках выше экрана, они падают не одновременно, создавая каскадный эффект. Низкое трение и высокая упругость приводят к длительному, хаотичному движению, пока энергия не рассеется, и тела не "уснут" благодаря enableSleeping.

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

Этот пример — отличная стартовая точка для экспериментов с 2D-физикой в играх. Попробуйте изменить параметры: задать setBounce(0.3) для более "тяжелых" мячей, увеличить setFriction до 0.1, чтобы объекты быстрее останавливались, или отключить гравитацию через this.matter.world.setGravity(0, 0). Можно также изменить форму тел с помощью setRectangle() или добавить взаимодействие с игроком, сделав мячи кликабельными и добавляя им импульс applyForce по клику.