О чем этот пример
Физика мягких тел (Soft Body) в Matter.js открывает путь к созданию реалистичных деформируемых объектов, таких как ткань, веревки или желе. В этой статье мы разберем пример создания физического полотна, которое динамично реагирует на столкновения с окружением. Этот подход полезен для разработки интерактивных элементов окружения, сложных разрушаемых объектов или нестандартных игровых механик.
Версия Phaser: код и демо в этой статье рассчитаны на Phaser 3.90.0.
Живой запуск
Ниже встроен рабочий билд примера. Оригинальный источник: GitHub.
Исходный код
class Example extends Phaser.Scene {
constructor() {
super();
}
preload()
{
this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
this.load.image('ball', 'assets/sprites/crate32.png');
this.load.spritesheet('balls', 'assets/sprites/balls.png', { frameWidth: 17, frameHeight: 17 });
}
create()
{
this.matter.world.setBounds();
this.matter.add.mouseSpring();
const group = this.matter.world.nextGroup(true);
const particleOptions = { friction: 0.00001, collisionFilter: { group: group }, render: { visible: false } };
const constraintOptions = { stiffness: 0.06 };
// softBody: function (x, y, columns, rows, columnGap, rowGap, crossBrace, particleRadius, particleOptions, constraintOptions)
this.cloth = this.matter.add.softBody(200, 140, 20, 12, 5, 5, false, 8, particleOptions, constraintOptions);
for (let i = 0; i < this.cloth.bodies.length; i++)
{
const body = this.cloth.bodies[i];
if (i < 20)
{
body.isStatic = true;
}
}
this.matter.add.circle(300, 500, 80, { isStatic: true, chamfer: { radius: 20 } });
this.matter.add.rectangle(500, 480, 80, 80, { isStatic: true });
this.matter.add.rectangle(400, 609, 800, 50, { isStatic: true });
}
}
const config = {
type: Phaser.AUTO,
width: 800,
height: 600,
backgroundColor: '#000000',
parent: 'phaser-example',
physics: {
default: 'matter',
matter: {
debug: true,
debugBodyColor: 0xffffff
}
},
scene: [ Example]
};
const game = new Phaser.Game(config);
Подготовка сцены и загрузка ресурсов
В методе preload мы задаем базовый URL для загрузки ассетов из репозитория примеров Phaser и загружаем два изображения. Одно изображение будет использоваться для статических тел, другое — как спрайтшит.
this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
this.load.image('ball', 'assets/sprites/crate32.png');
this.load.spritesheet('balls', 'assets/sprites/balls.png', { frameWidth: 17, frameHeight: 17 });
Обратите внимание, что в данном примере загруженные спрайты не используются напрямую для создания ткани, так как визуализация тел осуществляется в режиме отладки (debug: true). Основная цель preload в этом коде — демонстрация типичного пути загрузки ресурсов.
Настройка мира Matter и создание ткани
В методе create мы сначала настраиваем мир физики Matter: устанавливаем границы и добавляем пружину, привязанную к курсору мыши, для интерактивного взаимодействия с объектами.
this.matter.world.setBounds();
this.matter.add.mouseSpring();
Затем создается группа (group) для фильтра коллизий. Это гарантирует, что частицы, из которых состоит ткань, не будут сталкиваться друг с другом, что предотвращает нежелательное внутреннее трение и толчки.
const group = this.matter.world.nextGroup(true);
Далее определяются опции для частиц и соединительных ограничений (constraints). Низкое значение friction уменьшает трение, делая ткань более "скользкой". Высокая stiffness (жесткость) в ограничениях влияет на упругость соединений.
const particleOptions = { friction: 0.00001, collisionFilter: { group: group }, render: { visible: false } };
const constraintOptions = { stiffness: 0.06 };
Ключевой момент — вызов функции this.matter.add.softBody. Она создает сетку частиц, соединенных ограничениями. Параметры задают позицию (200, 140), размер сетки (20x12), расстояние между частицами (5, 5), отсутствие диагональных связей (crossBrace: false), радиус частицы (8) и ранее заданные опции.
this.cloth = this.matter.add.softBody(200, 140, 20, 12, 5, 5, false, 8, particleOptions, constraintOptions);
Фиксация верхнего края и создание препятствий
Чтобы ткань висела, а не падала бесформенной кучей, необходимо зафиксировать ее верхний край. В примере это делается путем перебора массивов созданных тел (this.cloth.bodies) и установки флага isStatic для первых 20 тел (что соответствует верхнему ряду сетки 20x12).
for (let i = 0; i < this.cloth.bodies.length; i++) {
const body = this.cloth.bodies[i];
if (i < 20) {
body.isStatic = true;
}
}
Затем на сцену добавляются статические препятствия разной формы: круг с фаской (chamfer), прямоугольник и длинная платформа внизу. Эти тела создают окружение, с которым будет взаимодействовать наша ткань.
this.matter.add.circle(300, 500, 80, { isStatic: true, chamfer: { radius: 20 } });
this.matter.add.rectangle(500, 480, 80, 80, { isStatic: true });
this.matter.add.rectangle(400, 609, 800, 50, { isStatic: true });
Конфигурация игры и физики
Весь пример работает благодаря правильной настройке конфигурации игры (config). Самое важное — активация физического движка Matter и включение режима отладки. Режим отладки (debug: true) визуализирует все физические тела (частицы и ограничения) вместо использования текстур, что идеально для прототипирования.
const config = {
type: Phaser.AUTO,
width: 800,
height: 600,
backgroundColor: '#000000',
parent: 'phaser-example',
physics: {
default: 'matter',
matter: {
debug: true,
debugBodyColor: 0xffffff
}
},
scene: [ Example ]
};
Что попробовать дальше
Используя matter.add.softBody, вы можете быстро создавать сложные деформируемые структуры. Для экспериментов попробуйте изменить параметры stiffness и friction, чтобы получить материал, похожий на резину, желе или мокрую ткань. Добавьте ветер, применив силу ко всем частицам тела, или замените отладочную отрисовку на прикрепление реальных спрайтов к каждой частице для создания визуально сложных интерактивных объектов.
