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

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

Версия 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');
    }

    create ()
    {
        const blockA = this.matter.add.image(0, 300, 'block').setBounce(1).setFriction(0);

        const blockB = this.matter.add.image(600, 300, 'block').setStatic(true);

        blockA.setVelocityX(10);

        this.matter.world.on('collisionstart', (event, bodyA, bodyB) =>
        {

            bodyA.gameObject.setTint(0xff0000);
            bodyB.gameObject.setTint(0x00ff00);

        });
    }
}

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

const game = new Phaser.Game(config);

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

В Phaser 3 для использования расширенного физического движка Matter.js необходимо правильно настроить конфигурацию игры. Основные параметры задаются в объекте physics.matter.

const config = {
    type: Phaser.AUTO,
    width: 800,
    height: 600,
    backgroundColor: '#1b1464',
    parent: 'phaser-example',
    physics: {
        default: 'matter', // Активируем Matter.js как физическую систему по умолчанию
        matter: {
            gravity: {
                x: 0, // Отключаем гравитацию по оси X
                y: 0  // Отключаем гравитацию по оси Y
            }
        }
    },
    scene: Example
};

Ключевой момент — свойство default: 'matter'. Оно сообщает Phaser, что нужно использовать Matter.js. Внутри объекта matter мы отключаем гравитацию (gravity: {x:0, y:0}), чтобы в нашем примере блок двигался строго по прямой, не падая.

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

После настройки движка мы можем создавать объекты, которые будут участвовать в физическом взаимодействии. В Matter.js для этого используется фабрика this.matter.add. В примере создаются два блока.

create ()
{
    // Создаем динамическое тело (blockA) с начальными координатами (0, 300)
    const blockA = this.matter.add.image(0, 300, 'block').setBounce(1).setFriction(0);
    // Создаем статическое тело (blockB), которое не будет двигаться от столкновений
    const blockB = this.matter.add.image(600, 300, 'block').setStatic(true);
    // Задаем начальную скорость для динамического блока
    blockA.setVelocityX(10);
}

Метод this.matter.add.image() создает спрайт, который одновременно является физическим телом. Для blockA задаются свойства setBounce(1) (идеальный отскок, энергия не теряется) и setFriction(0) (отсутствие трения). Метод setStatic(true) делает blockB неподвижным — он будет служить препятствием. blockA.setVelocityX(10) придает первому блоку постоянную скорость вправо, чтобы обеспечить столкновение.

Обработка события столкновения

Сердце примера — подписка на событие collisionstart. Это событие генерируется физическим миром this.matter.world в самый первый кадр, когда два тела начинают контактировать.

this.matter.world.on('collisionstart', (event, bodyA, bodyB) =>
{
    bodyA.gameObject.setTint(0xff0000); // Красим тело A в красный
    bodyB.gameObject.setTint(0x00ff00); // Красим тело B в зеленый
});

Колбэк-функция получает три аргумента: объект события event и два физических тела (bodyA и bodyB), которые столкнулись. Важно понимать, что bodyA и bodyB — это именно физические тела Matter.js. Чтобы получить ссылку на игровой объект Phaser (спрайт), к которому привязано тело, используется свойство gameObject. В примере мы используем метод setTint() этого игрового объекта для изменения его цвета, что служит наглядной визуальной реакцией на столкновение.

Порядок аргументов и важные детали

При работе с событием collisionstart стоит помнить о нескольких ключевых моментах, которые влияют на логику обработки.

// bodyA и bodyB — это физические тела, а не игровые объекты.
// Порядок, в котором они передаются в колбэк, не гарантирован.

1. **Аргументы bodyA и bodyB:** Это не ваши исходные спрайты (blockA, blockB), а внутренние физические тела движка Matter.js. Доступ к спрайту осуществляется через bodyA.gameObject. 2. **Порядок тел:** Не полагайтесь на то, что bodyA — это всегда первый движущийся объект. В одном столкновении blockA может быть bodyA, в другом — bodyB. Если логика должна различать объекты, используйте их пользовательские данные, тип или заранее заданные свойства. 3. **Момент срабатывания:** Событие происходит один раз в начале контакта. Пока тела соприкасаются, последующие кадры столкновения это событие вызывать не будут. Для отслеживания непрерывного контакта существует событие collisionactive.

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

Событие collisionstart — это мощный и простой в использовании инструмент для реагирования на начало физического взаимодействия в вашей игре. На его основе можно строить системы нанесения урона, сбора предметов, активации механизмов или проигрывания звуков. **Идеи для экспериментов:** 1. Вместо смены цвета попробуйте увеличивать счетчик при столкновении с определенным типом объекта, используя пользовательские данные тела (body.gameObject.setData('type', 'coin')). 2. Создайте цепную реакцию: при столкновении первого блока со вторым задавайте скорость третьему, неактивному блоку. 3. Используйте событие collisionend, чтобы отслеживать момент, когда объекты перестают соприкасаться, и, например, возвращать им исходный цвет.