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

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

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

Живой запуск

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

Исходный код


class Example extends Phaser.Scene
{
    block;
    cursors;
    preload ()
    {
        this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
        this.load.image('block', 'assets/sprites/block.png');
        this.load.image('ball', 'assets/sprites/shinyball.png');
    }

    create ()
    {
        this.block = this.matter.add.image(400, 50, 'block', null, { ignoreGravity: true });
        this.block.setFixedRotation();
        this.block.setMass(500);

        var y = 150;
        var prev = this.block;

        for (var i = 0; i < 12; i++)
        {
            var ball = this.matter.add.image(400, y, 'ball', null, { shape: 'circle', mass: 0.1 });

            this.matter.add.joint(prev, ball, (i === 0) ? 90 : 35, 0.4);

            prev = ball;

            y += 18;
        }

        this.matter.add.mouseSpring();

        this.cursors = this.input.keyboard.createCursorKeys();
    }

    update ()
    {
        if (this.cursors.left.isDown)
        {
            this.block.setVelocityX(-20);
        }
        else if (this.cursors.right.isDown)
        {
            this.block.setVelocityX(20);
        }
        else
        {
            this.block.setVelocityX(0);
        }

        if (this.cursors.up.isDown)
        {
            this.block.setVelocityY(-20);
        }
        else if (this.cursors.down.isDown)
        {
            this.block.setVelocityY(20);
        }
        else
        {
            this.block.setVelocityY(0);
        }
    }

}

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

const game = new Phaser.Game(config);

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

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

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

const game = new Phaser.Game(config);

В методе preload загружаются два спрайта: 'block' и 'ball'. Обратите внимание, что базовый URL указывает на репозиторий с примерами Phaser, откуда берутся изображения.

Создание якоря и первого звена

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

create () {
    this.block = this.matter.add.image(400, 50, 'block', null, { ignoreGravity: true });
    this.block.setFixedRotation();
    this.block.setMass(500);
}
*   `this.matter.add.image` создает физическое тело на основе изображения.
*   Опция `{ ignoreGravity: true }` делает блок невосприимчивым к гравитации, что позволяет нам управлять им независимо.
*   `setFixedRotation()` фиксирует вращение тела.
*   `setMass(500)` устанавливает большую массу, делая блок инертным якорем для будущей цепочки.

Генерация цепочки из шаров

Теперь создадим саму цепь. Мы будем в цикле создавать шары и соединять их последовательно с помощью joint (связи).

var y = 150;
var prev = this.block;

for (var i = 0; i < 12; i++)
{
    var ball = this.matter.add.image(400, y, 'ball', null, { shape: 'circle', mass: 0.1 });
    this.matter.add.joint(prev, ball, (i === 0) ? 90 : 35, 0.4);
    prev = ball;
    y += 18;
}

* prev хранит ссылку на предыдущее тело в цепочке. На первой итерации это наш блок-якорь. * Для каждого шара указывается форма 'circle' и небольшая масса (0.1), что делает их легкими и подвижными. * this.matter.add.joint создает связь между двумя телами. Третий параметр — это длина связи. Для первого звена между блоком и первым шаром она равна 90, для всех последующих — 35. * Четвертый параметр (0.4) — жесткость (stiffness) связи. Значение меньше 1 делает связь упругой, как у настоящей цепи. * Переменная `y` увеличивается на 18 пикселей за итерацию, располагая шары вертикально.

Интерактивность и управление

Чтобы можно было взаимодействовать с симуляцией, добавляются два инструмента: мышиная пружина и управление с клавиатуры.

this.matter.add.mouseSpring();
this.cursors = this.input.keyboard.createCursorKeys();

* this.matter.add.mouseSpring() добавляет возможность перетаскивать любые физические тела в сцене мышью. * createCursorKeys() инициализирует слушатель для стрелок клавиатуры.

Логика управления якорем реализована в методе update, который вызывается каждый кадр.

update ()
{
    if (this.cursors.left.isDown) { this.block.setVelocityX(-20); }
    else if (this.cursors.right.isDown) { this.block.setVelocityX(20); }
    else { this.block.setVelocityX(0); }

    if (this.cursors.up.isDown) { this.block.setVelocityY(-20); }
    else if (this.cursors.down.isDown) { this.block.setVelocityY(20); }
    else { this.block.setVelocityY(0); }
}

Методы setVelocityX и setVelocityY напрямую задают скорость тела. Движение якоря через эти методы передается по всей цепочке благодаря физическим связям.

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

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