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

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

Версия 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('mushroom', 'assets/sprites/mushroom2.png');
        this.load.image('flectrum', 'assets/sprites/flectrum.png');
    }

    create ()
    {
        const wall = this.physics.add.image(200, 300, 'flectrum').setImmovable();

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

        this.physics.add.collider(wall, sprite, function ()
        {
            wall.setAlpha(0.5);
        });
    }
}

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

const game = new Phaser.Game(config);

Настройка сцены и загрузка ассетов

Первым шагом является подготовка сцены: загрузка изображений и инициализация физики. В методе preload() мы указываем базовый URL и загружаем два спрайта: 'flectrum' (который станет стеной) и 'mushroom' (который будет двигаться).

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

Ключевой момент — конфигурация физики в объекте config. Мы используем Arcade Physics, отключаем гравитацию (gravity: { y: 0 }) и включаем отладку (debug: true), чтобы видеть хитбоксы. Это поможет визуально проверить столкновения.

Создание неподвижного объекта и движущегося спрайта

В методе create() мы создаем два физических тела. Спрайт 'flectrum' становится неподвижной стеной с помощью setImmovable(true). Это означает, что при столкновении его скорость и позиция не изменятся, даже если в него ударится другой объект.

const wall = this.physics.add.image(200, 300, 'flectrum').setImmovable();

Спрайт 'mushroom' создается с начальной скоростью (setVelocity(-100, 0)), отскоком (setBounce(1)) для идеального упругого столкновения и включенными границами мира (setCollideWorldBounds(true)). Он будет двигаться влево и отскакивать от краев экрана.

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

Настройка коллайдера и обработка столкновений

Для обнаружения столкновений между стеной и спрайтом используется this.physics.add.collider(). Этот метод автоматически обрабатывает физику взаимодействия: движущийся спрайт отскочит от неподвижной стены, сохраняя энергию благодаря setBounce(1).

this.physics.add.collider(wall, sprite, function ()
{
    wall.setAlpha(0.5);
});

В примере добавлен callback-функция, которая срабатывает при каждом столкновении: она уменьшает прозрачность стены (setAlpha(0.5)). Это демонстрирует, как можно легко добавить визуальную обратную связь на события физики. Без setImmovable() стена сдвигалась бы при ударе, нарушая логику барьера.

Почему это работает: физика Arcade в деталях

Phaser Arcade Physics рассчитывает столкновения на основе скоростей и масс объектов. Когда объект помечен как immovable, его масса считается бесконечной — поэтому при столкновении меняется только скорость движущегося объекта. В нашем примере 'mushroom' отскакивает от стены с той же скоростью (из-за setBounce(1)), а стена остается на месте.

Важно: setImmovable() не отключает физику для объекта — он все еще участвует в расчетах, но его позиция фиксирована. Это отличает его от статических тел, которые можно создать через this.physics.add.staticGroup(). Используйте setImmovable() для динамических объектов, которые должны временно стать барьерами, например, для блоков, которые можно активировать позже.

Распространенные ошибки и как их избежать

1. **Забыть setImmovable()**: Без этого оба спрайта будут двигаться при столкновении, что может не соответствовать задумке. 2. **Неверная конфигурация физики**: Убедитесь, что в config включен Arcade Physics, иначе методы this.physics.add не будут доступны. 3. **Путаница с координатами**: Объекты создаются в координатах (x, y) относительно левого верхнего угла. Проверяйте позиции, чтобы спрайты изначально не пересекались. 4. **Отсутствие отскока**: Если setBounce(0), спрайт просто остановится у стены. Для динамичных столкновений настройте отскок.

Пример корректной инициализации:

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

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

Использование setImmovable() в Phaser — это простой и эффективный способ создания стабильных барьеров в играх. Вы можете экспериментировать: измените setBounce() на меньшее значение для более реалистичного отскока, добавьте несколько неподвижных объектов для построения лабиринта или комбинируйте с другими физическими свойствами, например setFriction(). Для сложных сцен рассмотрите использование статических групп (staticGroup) для оптимизации.