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

Физический движок Phaser позволяет объектам взаимодействовать с границами игрового мира, но что если нужно не просто отскочить, а выполнить какое-то действие в момент касания? Например, изменить направление стрелки или запустить звуковой эффект. В этом примере мы используем событие `worldbounds` для мгновенной реакции на столкновение спрайта с любой из четырех границ сцены. Это полезно для создания точных игровых механик, где важно именно место столкновения, а не сам факт отскока.

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

    create ()
    {
        this.add.image(400, 300, 'bg');

        this.physics.add.sprite(200, 150, 'arrow')
            .setVelocity(200, -200)
            .setCollideWorldBounds(true, 1, 1, true);

        this.physics.world.on('worldbounds', (body, up, down, left, right) =>
        {
            const { gameObject } = body;

            if (up) { gameObject.setAngle(90); }
            else if (down) { gameObject.setAngle(-90); }
            else if (left) { gameObject.setAngle(0); }
            else if (right) { gameObject.setAngle(180); }
        });
    }
}

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

const game = new Phaser.Game(config);

Настройка физического спрайта

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

this.physics.add.sprite(200, 150, 'arrow')
    .setVelocity(200, -200)
    .setCollideWorldBounds(true, 1, 1, true);

Здесь мы создаем спрайт стрелки, задаем ему начальную скорость и говорим движку: "столкновение с границами мира включено, коэффициент восстановления по осям X и Y равен 1 (упругий отскок), и при столкновении генерируй событие".

Подписка на событие 'worldbounds'

Событие worldbounds генерируется объектом this.physics.world, который представляет собой мир физического движка Arcade. На это событие нужно подписаться, передав функцию-обработчик (callback).

this.physics.world.on('worldbounds', (body, up, down, left, right) =>
{
    // Логика обработки
});

В обработчик передается несколько аргументов: body — физическое тело объекта, столкнувшегося с границей, и четыре булевых флага (up, down, left, right). Эти флаги точно указывают, с какой именно границей произошло столкновение.

Логика реакции на столкновение

Внутри обработчика мы деструктурируем gameObject из переданного тела body. Это сам спрайт, связанный с физическим телом. Затем, проверяя флаги, мы меняем угол поворота этого спрайта (setAngle), чтобы стрелка всегда "смотрела" от границы, которую она только что задела.

const { gameObject } = body;

if (up) { gameObject.setAngle(90); }
else if (down) { gameObject.setAngle(-90); }
else if (left) { gameObject.setAngle(0); }
else if (right) { gameObject.setAngle(180); }

Например, если сработал флаг up (столкновение с верхней границей), устанавливаем угол 90 градусов, и стрелка смотрит вниз.

Настройка конфигурации игры

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

const config = {
    type: Phaser.AUTO,
    width: 800,
    height: 600,
    pixelArt: true,
    parent: 'phaser-example',
    physics: {
        default: 'arcade', // Используем Arcade Physics
        arcade: {
            debug: false   // Отключаем отладочную визуализацию
        }
    },
    scene: Example
};

Важно убедиться, что в объекте physics указан default: 'arcade'. Параметры width и height определяют размеры мира, границы которого (world bounds) будут проверяться.

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

Событие worldbounds — это мощный инструмент для создания детализированной обратной связи в игре. Оно позволяет реагировать не просто на факт отскока от края, а на конкретную сторону столкновения. Попробуйте расширить пример: добавляйте звуковые эффекты с помощью this.sound.play, создавайте частицы через this.add.particles при ударе или меняйте скорость объекта в зависимости от задетой границы.