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

Сенсоры — это особый тип физических тел, которые могут обнаруживать столкновения, но не участвуют в физическом взаимодействии. Это открывает широкие возможности для создания триггерных зон, областей поражения, детекторов подбора предметов и невидимых активаторов событий в вашей игре. В этой статье мы разберем пример из официальной документации 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('block', 'assets/sprites/block.png');
        this.load.image('platform', 'assets/sprites/platform.png');
    }

    create ()
    {
        this.matter.add.image(400, 150, 'platform').setStatic(true);
        this.matter.add.image(600, 350, 'platform').setStatic(true);
        this.matter.add.image(200, 550, 'platform').setStatic(true);

        this.player = this.matter.add.image(200, 300, 'block', null, { isSensor: true });

        this.matter.world.on('collisionstart', (event, bodyA, bodyB) =>
        {
            bodyA.gameObject.setTint(0xff0000);
        });

        this.matter.world.on('collisionend', (event, bodyA, bodyB) =>
        {
            bodyA.gameObject.setTint(0xffffff);
        });

        this.cursors = this.input.keyboard.createCursorKeys();

        this.add.text(10, 10, 'Move with cursor keys. Hit blocks with sensors.', { font: '16px Courier', fill: '#ffffff' });
    }

    update ()
    {
        if (this.cursors.left.isDown)
        {
            this.player.setVelocityX(-10);
        }
        else if (this.cursors.right.isDown)
        {
            this.player.setVelocityX(10);
        }
        else
        {
            this.player.setVelocityX(0);
        }

        if (this.cursors.up.isDown)
        {
            this.player.setVelocityY(-10);
        }
        else if (this.cursors.down.isDown)
        {
            this.player.setVelocityY(10);
        }
        else
        {
            this.player.setVelocityY(0);
        }
    }
}

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

const game = new Phaser.Game(config);

Настройка физики Matter.js

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

Мы отключаем гравитацию по оси Y, чтобы упростить управление объектом с клавиатуры, и включаем режим отладки debug: true, который визуализирует физические тела.

physics: {
    default: 'matter',
    matter: {
        debug: true,
        gravity: {
            y: 0
        }
    }
}

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

В методе create() сцены создаются статические платформы и главный объект — игрок. Ключевое отличие в создании игрока — пятый параметр, объект дополнительных настроек Matter тела { isSensor: true }.

Свойство isSensor: true сообщает движку, что это тело должно только регистрировать пересечения (коллизии), но не оказывать и не получать физического ответа (отталкивание, трение). Платформы же создаются как обычные статические тела. Метод setStatic(true) делает тело неподвижным.

this.matter.add.image(400, 150, 'platform').setStatic(true);
this.matter.add.image(600, 350, 'platform').setStatic(true);
this.matter.add.image(200, 550, 'platform').setStatic(true);

this.player = this.matter.add.image(200, 300, 'block', null, { isSensor: true });

Обработка событий коллизий

Для реакции на пересечение сенсора с другими телами Matter.js предоставляет события collisionstart и collisionend. Они срабатывают на уровне мира this.matter.world.

В обработчике события collisionstart тело bodyA (которое является телом нашего игрока-сенсора) получает ссылку на свой игровой объект (gameObject), и этому объекту устанавливается красный оттенок. Когда коллизия заканчивается (collisionend), оттенок сбрасывается на белый.

Важно: в этом примере сенсор всегда передается как bodyA. В реальном проекте нужно проверять, какое из столкнувшихся тел является сенсором.

this.matter.world.on('collisionstart', (event, bodyA, bodyB) =>
{
    bodyA.gameObject.setTint(0xff0000);
});

this.matter.world.on('collisionend', (event, bodyA, bodyB) =>
{
    bodyA.gameObject.setTint(0xffffff);
});

Управление сенсором

Поскольку сенсор не сталкивается с окружением, управлять им можно, напрямую задавая скорость. В методе update() мы проверяем состояние клавиш-стрелок и с помощью setVelocityX() и setVelocityY() устанавливаем соответствующую скорость для тела игрока.

Если ни одна клавиша не нажата, скорость сбрасывается до нуля, что останавливает объект.

if (this.cursors.left.isDown)
{
    this.player.setVelocityX(-10);
}
else if (this.cursors.right.isDown)
{
    this.player.setVelocityX(10);
}
else
{
    this.player.setVelocityX(0);
}
// ... аналогично для оси Y

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

Сенсоры в Matter.js — мощный инструмент для создания логики игры, не связанной напрямую с физикой столкновений. Вы можете использовать их для зон финиша, ловушек, диалоговых триггеров или областей, наносящих периодический урон. Для экспериментов попробуйте сделать сенсор не кругом, а сложной полигональной формой, создать несколько сенсоров с разными реакциями или использовать событие collisionactive для непрерывного действия (например, медленного отнимания здоровья) пока объект находится в зоне.