О чем этот пример
При разработке сложных игровых миров часто возникает необходимость в тонком контроле за тем, какие объекты должны сталкиваться друг с другом. Простая физика «все со всем» здесь не подходит. Встроенный в Phaser движок 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(200, 300, 'block').setBounce(1).setFriction(0);
const blockB = this.matter.add.image(400, 300, 'block');
const blockC = this.matter.add.image(750, 300, 'block').setStatic(true);
const blockD = this.matter.add.image(50, 300, 'block').setStatic(true);
const cat1 = this.matter.world.nextCategory();
blockA.setCollisionCategory(cat1);
blockC.setCollisionCategory(cat1);
const cat2 = this.matter.world.nextCategory();
blockD.setCollisionCategory(cat2);
blockA.setCollidesWith([ cat1, cat2 ]);
// blockA.setCollidesWith(cat1);
blockA.setVelocityX(25);
this.matter.world.on('collisionstart', event =>
{
event.pairs[0].bodyA.gameObject.setTint(0xff0000);
event.pairs[0].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 использует битовую маску для фильтрации коллизий. Каждому физическому телу можно назначить категорию (один бит) и маску коллизий (набор битов). Столкновение произойдет, если категория тела A присутствует в маске коллизий тела B, и наоборот.
Phaser упрощает работу с этой системой. Метод this.matter.world.nextCategory() автоматически генерирует новую уникальную категорию (сдвигая бит), избавляя разработчика от ручного подсчета.
const cat1 = this.matter.world.nextCategory();
const cat2 = this.matter.world.nextCategory();
Назначение категорий объектам
Созданные категории назначаются физическим телам с помощью метода setCollisionCategory(). В примере мы видим четыре блока. Два из них (blockA и blockC) относятся к категории cat1, а один статичный блок (blockD) — к категории cat2. Блок blockB не получает явной категории, а значит, использует категорию по умолчанию.
blockA.setCollisionCategory(cat1);
blockC.setCollisionCategory(cat1);
blockD.setCollisionCategory(cat2);
Определение правил столкновений
Ключевой метод setCollidesWith() определяет, с какими категориями может сталкиваться данный объект. Он принимает либо одну категорию, либо массив категорий. В исходном коде blockA настроен на столкновение и с cat1, и с cat2.
Это значит, что движущийся blockA будет взаимодействовать с блоком blockC (оба в cat1) и с блоком blockD (в cat2). При этом blockA проигнорирует blockB, так как его категория по умолчанию не входит в список разрешенных для blockA.
blockA.setCollidesWith([ cat1, cat2 ]);
// Альтернативная запись для одной категории:
// blockA.setCollidesWith(cat1);
Обработка событий столкновения
Для визуализации и обработки коллизий в примере используется событие collisionstart мира Matter. В обработчике события event.pairs содержит массив пар столкнувшихся тел. Каждому игровому объекту в паре назначается tint для наглядности.
this.matter.world.on('collisionstart', event => {
event.pairs[0].bodyA.gameObject.setTint(0xff0000);
event.pairs[0].bodyB.gameObject.setTint(0x00ff00);
});
Настройка сцены и физики
Для работы с Matter.js необходимо правильно сконфигурировать физический плагин в настройках игры. В примере гравитация отключена (установлена в 0), чтобы движение блока blockA было равномерным.
const config = {
// ... другие настройки
physics: {
default: 'matter',
matter: {
gravity: { x: 0, y: 0 }
}
},
scene: Example
};
Что попробовать дальше
Фильтры коллизий Matter.js — это точный инструмент для создания сложной игровой логики. Вы можете создавать слои объектов, которые существуют в одном пространстве, но не мешают друг другу (например, фоновые декорации), или, наоборот, настраивать избирательное взаимодействие (как ключ с определенной дверью). Для экспериментов попробуйте: создать более двух категорий; настроить setCollidesWith для статичных объектов; сделать так, чтобы объекты одной категории отталкивались, а разных — притягивались, комбинируя фильтры с силами (applyForce).
