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

Phaser предоставляет мощную, но простую в использовании систему Arcade Physics. Часто разработчики ограничиваются базовыми свойствами вроде скорости и отскока. Однако прямое взаимодействие с объектом `Phaser.Physics.Arcade.Body` открывает огромные возможности для тонкой настройки поведения объектов — от имитации физических свойств до дебаггинга. В этой статье мы разберем пример, демонстрирующий доступ к десяткам свойств физического тела и создание для них интерактивного интерфейса. Это позволит вам быстро прототипировать поведение объектов и глубоко понимать работу физического движка.

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

Живой запуск

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

Исходный код


class Example extends Phaser.Scene
{
    sprite;

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

    create ()
    {
        this.sprite = this.physics.add.image(400, 300, 'mushroom')
            .setBounce(1, 1)
            .setVelocityX(300);

        const block = this.physics.add.staticImage(400, 450, 'block');

        this.physics.add.collider(this.sprite, block);

        this.createBodyGui(this.sprite.body);
    }

    update ()
    {
        this.physics.world.wrap(this.sprite);
    }

    createBodyGui (body)
    {
        const gui = new dat.GUI({ width: 600 });

        gui.add(body, 'allowDrag');
        gui.add(body, 'allowGravity');
        gui.add(body, 'allowRotation');
        gui.add(body, 'angularAcceleration', -360, 360, 5);
        gui.add(body, 'angularVelocity', -360, 360, 5);
        gui.add(body, 'collideWorldBounds');
        gui.add(body, 'debugShowBody');
        gui.add(body, 'debugShowVelocity');
        gui.add(body, 'enable');
        gui.add(body, 'immovable');
        gui.add(body, 'isCircle');
        gui.add(body, 'mass', 0.1, 10, 0.1);
        gui.add(body, 'moves');
        gui.add(body, 'useDamping');
        gui.addColor(body, 'debugBodyColor');

        this.createVectorGui(gui, 'acceleration', body.acceleration, -600, 600, 10);
        this.createVectorGui(gui, 'bounce', body.bounce, 0, 1, 0.1);
        this.createVectorGui(gui, 'deltaMax', body.deltaMax, 0, 60, 1);
        this.createVectorGui(gui, 'drag', body.drag, 0, 60, 0.1);
        this.createVectorGui(gui, 'friction', body.friction, 0, 1, 0.05);
        this.createVectorGui(gui, 'gravity', body.gravity, -600, 600, 10);
        this.createVectorGui(gui, 'maxVelocity', body.maxVelocity, 0, 10000, 100);
        this.createVectorGui(gui, 'velocity', body.velocity, -600, 600, 10);

        const check = gui.addFolder('checkCollision');
        check.add(body.checkCollision, 'left');
        check.add(body.checkCollision, 'up');
        check.add(body.checkCollision, 'right');
        check.add(body.checkCollision, 'down');

        return gui;
    }

    createVectorGui (gui, name, vector, min, max, step)
    {
        const folder = gui.addFolder(name);

        folder.add(vector, 'x', min, max, step);
        folder.add(vector, 'y', min, max, step);

        return folder;
    }
}

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

const game = new Phaser.Game(config);

Создание физических объектов и базовый сценарий

Пример начинается с классической настройки сцены и создания двух объектов с физикой: динамического спрайта и статического блока. Ключевой момент — использование методов this.physics.add.image и this.physics.add.staticImage. Они автоматически создают и присоединяют физическое тело к спрайту.

this.sprite = this.physics.add.image(400, 300, 'mushroom')
    .setBounce(1, 1)
    .setVelocityX(300);

const block = this.physics.add.staticImage(400, 450, 'block');

Спрайту mushroom сразу задается высокий отскок (setBounce(1,1)) и начальная скорость по оси X. Статический блок не будет реагировать на силы и столкновения, оставаясь неподвижным. Далее создается коллайдер, который обеспечивает физическое взаимодействие между этими объектами.

this.physics.add.collider(this.sprite, block);

В методе update() используется this.physics.world.wrap, который "заворачивает" спрайт на противоположную сторону мира, если он его покидает, создавая эффект бесконечного пространства.

Доступ к телу и GUI для настройки

Сердце примера — метод createBodyGui(body). В него передается объект this.sprite.body, который является экземпляром Phaser.Physics.Arcade.Body. Этот объект содержит все физические свойства спрайта.

Для интерактивного изменения этих свойств используется библиотека dat.GUI. Каждый вызов gui.add() добавляет ползунок или переключатель для конкретного свойства тела. Например:

gui.add(body, 'allowDrag'); // Разрешает/запрещает сопротивление

Свойства можно разделить на несколько категорий: - **Флаги и состояния**: allowGravity, allowRotation, collideWorldBounds, enable, immovable, moves. - **Дебаггинг**: debugShowBody, debugShowVelocity, debugBodyColor. - **Скалярные значения**: angularAcceleration, angularVelocity, mass. - **Векторные значения**: acceleration, bounce, gravity, velocity.

Особого внимания заслуживает объект checkCollision, который позволяет тонко управлять тем, с каких сторон объект будет сталкиваться с другими телами.

const check = gui.addFolder('checkCollision');
check.add(body.checkCollision, 'left');
check.add(body.checkCollision, 'up');
check.add(body.checkCollision, 'right');
check.add(body.checkCollision, 'down');

Работа с векторными свойствами

Многие важные физические параметры, такие как скорость (velocity) или ускорение (acceleration), представлены в виде объектов с полями `xиy. Для их удобной настройки создан вспомогательный методcreateVectorGui`.

createVectorGui (gui, name, vector, min, max, step)
{
    const folder = gui.addFolder(name);
    folder.add(vector, 'x', min, max, step);
    folder.add(vector, 'y', min, max, step);
    return folder;
}

Этот метод создает в GUI отдельную папку для каждого векторного свойства и добавляет в нее два ползунка — для компоненты X и компоненты Y. Например, вызов для настройки скорости выглядит так:

this.createVectorGui(gui, 'velocity', body.velocity, -600, 600, 10);

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

Конфигурация игры и физики

Важнейший этап — правильная конфигурация игры. В примере используется Arcade Physics в качестве системы по умолчанию.

const config = {
    type: Phaser.AUTO,
    width: 800,
    height: 600,
    parent: 'phaser-example',
    physics: {
        default: 'arcade',
        arcade: { debug: true } // Включаем режим отладки
    },
    scene: Example
};

Установка debug: true для arcade крайне важна для этого примера. Именно это позволяет визуализировать физические тела (контуры) и векторы скорости при включении соответствующих свойств debugShowBody и debugShowVelocity в GUI. Без этой настройки дебаг-визуализация отображаться не будет.

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

Прямой доступ к объекту Body в Arcade Physics — это мощный инструмент для создания разнообразного и реалистичного поведения объектов. Этот пример служит отличной песочницей для экспериментов: попробуйте отключить гравитацию (allowGravity: false) и задать собственное ускорение, создайте объект с огромной массой (mass: 10), который будет толкать другие, или включите демпфирование (useDamping: true) для более плавного движения. Понимание этих свойств позволит вам не просто использовать физику, а полностью контролировать её в своих играх.