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

Разработчики часто выбирают между простотой Arcade Physics и реализмом Matter.js. Но что, если использовать обе системы одновременно в одной сцене? Это открывает уникальные возможности: например, создать статичный мир с продвинутой физикой Matter для окружения и динамичных объектов, и добавить несколько простых спрайтов с быстрой Arcade-физикой для UI-элементов или частиц. В этой статье мы разберем пример, где в одной сцене мирно сосуществуют два физических движка, и объясним, как это работает на практике.

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

Живой запуск

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

Исходный код


class Example extends Phaser.Scene
{
    constructor ()
    {
        super({
            key: 'Example',
            physics: {
                arcade: {
                    debug: true,
                    gravity: { y: 200 }
                },
                matter: {
                    debug: true,
                    gravity: { y: 0.5 }
                }
            }
        });
    }

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

    create ()
    {
        //  Matter JS:
        this.matter.add.image(400, -100, 'block');
        this.matter.add.image(360, -600, 'block');
        this.matter.add.image(420, -900, 'block');

        this.matter.add.image(400, 550, 'platform', null, { isStatic: true });

        //  Arcade Physics:
        const block = this.physics.add.image(400, 100, 'fuji');

        block.setVelocity(100, 200);
        block.setBounce(1, 1);
        block.setCollideWorldBounds(true);
    }
}

const config = {
    type: Phaser.AUTO,
    width: 800,
    height: 600,
    parent: 'phaser-example',
    scene: Example
};

const game = new Phaser.Game(config);

Настройка сцены с двумя движками

Ключевой момент — одновременная активация обеих физических систем в конфигурации сцены. Это делается в конструкторе класса сцены.

constructor ()
{
    super({
        key: 'Example',
        physics: {
            arcade: {
                debug: true,
                gravity: { y: 200 }
            },
            matter: {
                debug: true,
                gravity: { y: 0.5 }
            }
        }
    });
}

Обрати внимание на параметры gravity. В Arcade гравитация задается в пикселях в секунду (y: 200), а в Matter — в метрах в секунду в квадрате (y: 0.5). Это фундаментальное различие между упрощенной и реалистичной физикой. Флаг debug: true включает отладочную отрисовку для обеих систем, что помогает визуализировать физические тела.

Создание статических и динамических тел в Matter.js

Объекты Matter.js создаются через фабричный метод this.matter.add. В примере три динамических блока создаются за верхней границей экрана (с отрицательной координатой Y), чтобы они упали под действием гравитации.

this.matter.add.image(400, -100, 'block');
this.matter.add.image(360, -600, 'block');
this.matter.add.image(420, -900, 'block');

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

this.matter.add.image(400, 550, 'platform', null, { isStatic: true });

Четвертый аргумент (null) — это ключ кадра, который нам не нужен, так как используется вся текстура.

Добавление спрайта с Arcade Physics

В той же сцене мы создаем отдельный объект, управляемый движком Arcade. Он существует независимо от тел Matter.

const block = this.physics.add.image(400, 100, 'fuji');

После создания мы настраиваем его физические свойства. setVelocity задает начальную скорость по осям X и Y. setBounce(1, 1) устанавливает коэффициент упругости (1 — идеальный отскок, без потер энергии). setCollideWorldBounds(true) включает столкновения с границами мира, определенными в конфиге игры (800x600).

block.setVelocity(100, 200);
block.setBounce(1, 1);
block.setCollideWorldBounds(true);

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

Когда это полезно на практике?

1. **Прототипирование и отладка:** Можно быстро добавить объект с простой физикой (Arcade) для тестирования логики, не затрагивая сложную систему Matter. 2. **Гибридный геймдизайн:** Основной игровой мир с реалистичной физикой (Matter) для разрушаемых конструкций, верёвок, жидкостей. А элементы интерфейса, бонусы или простые враги используют легковесную физику Arcade. 3. **Визуальные эффекты:** Частицы дыма, искры или монетки за очками, которым нужна лишь базовая траектория и отскоки, идеально ложатся на Arcade, не нагружая точную, но ресурсоёмкую симуляцию Matter.

Основное правило: объекты разных движков не могут физически влиять друг на друга. Их взаимодействие должно быть запрограммировано вручную на уровне игровой логики.

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

Использование Arcade и Matter.js в одной сцене — мощный приём для создания гибкой и производительной физической модели игры. Начни экспериментировать: создай сцену, где платформы — это статические тела Matter, враги используют Arcade для простого патрулирования, а разрушаемые объекты (ящики) — динамические тела Matter. Попробуй вручную синхронизировать их состояния, например, чтобы событие столкновения в Matter запускало создание эффектов частиц через Arcade.