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

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

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

    create ()
    {
        const atari = this.physics.add.image(250, 200, 'atari');

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

        // This enables the world 'overlap' event, which will be detected by the collider below.
        sprite.body.onOverlap = true;

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

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

        // Static bodies must be updated manually if their parent game objects are moved.
        balls.refresh();

        this.physics.add.overlap(sprite, atari);
        this.physics.add.overlap(sprite, balls);

        this.physics.world.on('overlap', (gameObject1, gameObject2, body1, body2) =>
        {
            gameObject1.setAlpha(0.5);
            gameObject2.setAlpha(0.5);
        });
    }
}

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

const game = new Phaser.Game(config);

Подготовка сцены и объектов

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

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

// Это включает событие 'overlap' для данного тела, которое будет обнаружено коллайдером.
sprite.body.onOverlap = true;

Без установки onOverlap = true на теле, событие глобально не сработает, даже если коллайдер overlap добавлен. Также создается статическая группа (staticGroup) из 30 шаров, размещенных по прямоугольнику.

Настройка детекторов перекрытия (коллайдеров)

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

this.physics.add.overlap(sprite, atari);
this.physics.add.overlap(sprite, balls);

Здесь мы говорим движку: отслеживай перекрытие между спрайтом sprite и объектом atari, а также между sprite и любым шаром из группы balls. При обнаружении пересечения будет вызвано глобальное событие.

Глобальная обработка события 'overlap'

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

this.physics.world.on('overlap', (gameObject1, gameObject2, body1, body2) =>
{
    gameObject1.setAlpha(0.5);
    gameObject2.setAlpha(0.5);
});

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

Важные нюансы и отладка

1. **Статические тела требуют обновления**: Если статический объект (или группа) перемещается после создания, необходимо вызвать .refresh() для обновления физического тела в мире.

balls.refresh();

2. **Включение события на теле**: Помните, что body.onOverlap = true нужно выставить для каждого динамического тела, которое должно инициировать событие. 3. **Отладка**: В конфигурации Arcade Physics можно включить debug: true, чтобы видеть хитбоксы тел и убедиться, что перекрытие происходит так, как ожидается.

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

Событие overlap в Arcade Physics — мощный инструмент для создания нефизических взаимодействий: от сбора монет до зон активации. Для экспериментов попробуйте: изменить логику в обработчике события (например, уничтожать один из объектов), добавить проверку типов объектов через gameObject1.texture.key или управлять событием overlap для разных пар объектов с разными callback-функциями, передаваемыми непосредственно в this.physics.add.overlap().