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

В физическом движке Arcade Phaser 3 объекты могут отскакивать от границ игрового мира. Но что, если нужно не просто отскочить, а выполнить какое-то действие — например, сменить анимацию или воспроизвести звук? В этой статье мы разберем пример, который показывает, как добавить собственную логику при столкновении спрайта с краем экрана, используя событие '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.spritesheet('gameboy', 'assets/sprites/gameboy_seize_color_40x60.png', { frameWidth: 40, frameHeight: 60 });
        this.load.spritesheet('fish', 'assets/sprites/fish-136x80.png', { frameWidth: 136, frameHeight: 80 });
    }

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

        const gameboy = this.physics.add.image(200, 300, 'gameboy')
            .setVelocity(200, 150)
            .setCollideWorldBounds(true, 1, 1, true);

        const fish = this.physics.add.image(600, 300, 'fish')
            .setVelocity(150, 200)
            .setCollideWorldBounds(true, 1, 1, true);

        gameboy.onWorldBounds = function ()
        {
            this.setFrame((this.frame.name + 1) % 5);
        };

        fish.onWorldBounds = function ()
        {
            this.setFrame((this.frame.name + 1) % 3);
        };

        this.physics.world.on('worldbounds', (body) =>
        {
            body.gameObject.onWorldBounds();
        });
    }
}

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

const game = new Phaser.Game(config);

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

В методе preload() загружаются необходимые ресурсы: фон (изображение 'bg') и два спрайтшита ('gameboy' и 'fish'). Спрайтшиты загружаются с указанием размеров кадра через параметры frameWidth и frameHeight. Это позволяет в дальнейшем переключать кадры (frames) внутри этих листов спрайтов. Важно: метод setBaseURL закомментирован, значит, пути к ассетам указаны относительно текущей структуры проекта.

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

В методе create() добавляется фон. Затем создаются два физических спрайта (gameboy и fish) через this.physics.add.image. Им сразу задается начальная скорость с помощью setVelocity и включается столкновение с границами мира через setCollideWorldBounds(true, 1, 1, true). Последний параметр (true) означает, что объект будет отражаться от границ (bounce). Первые две единицы — это коэффициенты отскока по осям X и Y.

Определение кастомной логики при столкновении

Каждому объекту присваивается пользовательский метод onWorldBounds. Для gameboy этот метод увеличивает номер текущего кадра на 1, зацикливаясь по модулю 5 (так как в спрайтшите 5 кадров). Для fish логика аналогичная, но кадров всего 3. Это позволяет менять изображение спрайта каждый раз при ударе о границу мира. Метод setFrame изменяет текущий отображаемый кадр спрайтшита.

Подписка на событие мира physics.world

Ключевой момент: физический мир (this.physics.world) генерирует событие 'worldbounds' каждый раз, когда любое тело, у которого включено collideWorldBounds, сталкивается с границей. Мы подписываемся на это событие. В обработчике получаем тело (body), а через body.gameObject — ссылку на сам игровой объект (наш спрайт). Затем вызываем его пользовательский метод onWorldBounds(). Таким образом, вся кастомная логика выполняется автоматически при столкновении.

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

В конфигурации игры (config) активируется физический движок 'arcade' с отладочным режимом debug: false и гравитацией по оси Y. Гравитация влияет на движение объектов, но в данном примере они также имеют начальную скорость и отскакивают от границ, создавая хаотичное движение. Ширина и высота мира определяются параметрами width и height (800x600).

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

Используя событие 'worldbounds' физического мира Arcade, вы можете легко добавлять любые реакции на столкновения объектов с краем экрана. Это мощный инструмент для создания визуальных эффектов, звукового сопровождения или изменения игрового состояния. Для экспериментов попробуйте

  1. Добавить воспроизведение звука в метод onWorldBounds
  2. Изменять не только кадр, но и, например, цвет или размер спрайта
  3. Реализовать разные реакции для разных типов объектов, проверяя их тип или текстуру