О чем этот пример
Создание отзывчивого и интерактивного игрового мира невозможно без обработки физических взаимодействий. Событие `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, чтобы отслеживать момент, когда объекты перестают соприкасаться, и, например, возвращать им исходный цвет.
