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

При разработке игр часто требуется создать статичное препятствие или платформу. В Arcade Physics Phaser для этого есть свойство `immovable`. Однако в версии 3.60 был обнаружен баг (#7054), при котором круговые тела (`setCircle`) с этим свойством не работали корректно при столкновениях. Эта статья разбирает пример кода, демонстрирующий проблему и её автоматическое исправление в более поздних версиях движка. Понимание этой механики полезно для создания стабильных физических взаимодействий.

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

Живой запуск

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

Исходный код


class MainScene extends Phaser.Scene
{

    constructor()
    {
        super({ key: "MainScene" });
    }

    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/block.png');
    }

    create ()
    {
        const mushroom = this.physics.add.image(200, 350, 'mushroom')
            .setCircle(30)
            .setImmovable(true);

        const block = this.physics.add.image(500, 300, 'block')
            .setVelocity(-100, 0)
            .setBounce(1)
            .setCollideWorldBounds(true);

        this.physics.add.collider(mushroom, block);
    }
}

const config = {
    type: Phaser.AUTO,
    parent: 'phaser-example',
    width: 800,
    height: 600,
    physics: {
        default: 'arcade',
        arcade: {
            debug: true,
        }
    },
    scale: {
        mode: Phaser.Scale.FIT,
        autoCenter: Phaser.Scale.CENTER_BOTH
    },
    scene: [ MainScene ]
};

const game = new Phaser.Game(config);

Суть проблемы: недвижимое ≠ неподвижное

Свойство .setImmovable(true) не делает тело абсолютно статичным. Вместо этого оно указывает физическому движку, что при столкновении это тело не должно получать импульс от удара. Его скорость и положение не пересчитываются. Однако другое тело (подвижное) должно от него оттолкнуться.

В баге #7054 круглое тело с immovable: true игнорировало столкновения: подвижный объект просто проходил сквозь него. Это нарушало базовую логику игровой физики.

Разбор примера: настройка сцены

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

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/block.png');
}

Создание физических тел

В методе create создаются два физических тела. Ключевой момент: гриб (mushroom) делается недвижимым и его хитбокс задаётся в виде круга. Блок (block) получает начальную скорость.

const mushroom = this.physics.add.image(200, 350, 'mushroom')
    .setCircle(30)
    .setImmovable(true);

const block = this.physics.add.image(500, 300, 'block')
    .setVelocity(-100, 0)
    .setBounce(1)
    .setCollideWorldBounds(true);

Вызов .setCircle(30) заменяет прямоугольный хитбокс спрайта на круговой с радиусом 30 пикселей. Блок настроен отскакивать от границ мира (setCollideWorldBounds) и от других тел (setBounce(1)) без потери энергии.

Настройка коллизии

Столкновение между телами регистрируется с помощью this.physics.add.collider. Это главный метод для обработки отскоков и наложения в Arcade Physics.

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

При исправленном поведении (после версии 3.60) блок должен отскакивать от недвижимого гриба, как от стены. В багнутой версии коллайдер не срабатывал для кругового immovable тела.

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

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

physics: {
    default: 'arcade',
    arcade: {
        debug: true, // Визуализация хитбоксов
    }
}

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

Баги в низкоуровневых системах, вроде физики, могут кардинально ломать геймплей. Пример с недвижимым кругом — отличный урок: всегда тестируйте специфические комбинации свойств (setCircle + setImmovable). Для экспериментов попробуйте изменить радиус круга, убрать setImmovable или заменить круг на прямоугольный хитбокс (setSize), чтобы увидеть разницу в поведении. Актуальные версии Phaser (3.60+) содержат исправление этого бага, и столкновения работают корректно.