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

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

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

Живой запуск

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

Исходный код


class Example extends Phaser.Scene
{
    group;
    sprite;

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

    create ()
    {
        this.sprite = this.physics.add.image(400, 300, 'mushroom')
            .setVelocity(100, 200)
            .setBounce(1, 1)
            .setCollideWorldBounds(true)
            .setGravityY(200);

        this.group = this.physics.add.staticGroup({
            key: 'ball',
            frameQuantity: 30
        });

        Phaser.Actions.PlaceOnRectangle(this.group.getChildren(), new Phaser.Geom.Rectangle(84, 84, 616, 416));

        this.group.refresh();

        this.physics.add.overlap(this.sprite, this.group);
    }

    update ()
    {
        this.sprite.body.debugBodyColor = this.sprite.body.touching.none ? 0x0099ff : 0xff9900;
    }
}

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

const game = new Phaser.Game(config);

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

В классе сцены объявляются два свойства: group для статичных объектов и sprite для движущегося спрайта. В методе preload() загружаются два изображения, которые будут использоваться как текстуры.

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

Создание физических тел и группы

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

this.sprite = this.physics.add.image(400, 300, 'mushroom')
    .setVelocity(100, 200)
    .setBounce(1, 1)
    .setCollideWorldBounds(true)
    .setGravityY(200);

Затем создается статичная группа (staticGroup). Статичные тела не двигаются под действием физики, но могут участвовать в обнаружении столкновений. Здесь группа инициализируется с 30 одинаковыми спрайтами.

this.group = this.physics.add.staticGroup({
    key: 'ball',
    frameQuantity: 30
});

Расположение объектов и настройка overlap

Спрайты из группы размещаются по периметру прямоугольника с помощью утилиты Phaser.Actions.PlaceOnRectangle. После изменения позиции статичных тел необходимо вызвать refresh() для обновления их физических границ (AABB).

Phaser.Actions.PlaceOnRectangle(this.group.getChildren(), new Phaser.Geom.Rectangle(84, 84, 616, 416));
this.group.refresh();

Ключевая строка — создание детектора перекрытия между спрайтом и группой. Метод this.physics.add.overlap() начинает проверять пересечение их тел каждый кадр, но без физической реакции (объекты не отталкиваются).

this.physics.add.overlap(this.sprite, this.group);

Визуальная индикация контакта

В методе update(), который выполняется каждый кадр, меняется цвет отладки физического тела спрайта. Свойство body.touching.none равно true, если тело ни с чем не контактирует в текущем кадре. В зависимости от этого выбирается синий (0x0099ff) или оранжевый (0xff9900) цвет.

update ()
{
    this.sprite.body.debugBodyColor = this.sprite.body.touching.none ? 0x0099ff : 0xff9900;
}

Важно: эта визуализация работает только при включенной отладке физики в конфигурации игры (arcade: {debug: true}).

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

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

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

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

Метод overlap() — это легковесный инструмент для событийного программирования, когда физическое столкновение не требуется. Он идеально подходит для триггеров, сбора предметов или зон поражения. Для экспериментов попробуйте добавить коллбэк-функцию третьим аргументом в overlap(), чтобы выполнять код при каждом контакте, или используйте collider() вместо overlap(), чтобы объекты отталкивались друг от друга.