О чем этот пример
Реалистичная физика — ключ к увлекательному игровому процессу. Встроенные в Matter.js примитивы вроде кругов и прямоугольников часто не подходят для сложных игровых объектов. В этой статье мы разберем, как загружать и использовать точно соответствующие спрайту полигональные коллайдеры, созданные во внешнем редакторе PhysicsEditor. Этот подход значительно повышает реализм взаимодействий, когда объекты должны сталкиваться и падать в соответствии со своей визуальной формой, а не упрощенным bounding box.
Версия Phaser: код и демо в этой статье рассчитаны на Phaser 3.90.0.
Живой запуск
Ниже встроен рабочий билд примера. Оригинальный источник: GitHub.
Исходный код
class Example extends Phaser.Scene
{
preload ()
{
this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
// Load sprite sheet generated with TexturePacker
this.load.atlas('sheet', 'assets/physics/fruit-sprites.png', 'assets/physics/fruit-sprites.json');
// Load body shapes from JSON file generated using PhysicsEditor
this.load.json('shapes', 'assets/physics/fruit-shapes.json');
}
create ()
{
this.matter.world.setBounds(0, 0, 600, 800);
const shapes = this.cache.json.get('shapes');
this.add.image(0, 0, 'sheet', 'background').setOrigin(0, 0);
const ground = this.matter.add.sprite(0, 0, 'sheet', 'ground', { shape: shapes.ground });
this.matter.alignBody(ground, 300, 800, Phaser.Display.Align.BOTTOM_CENTER);
this.matter.add.sprite(200, 50, 'sheet', 'crate', { shape: shapes.crate });
this.matter.add.sprite(250, 250, 'sheet', 'banana', { shape: shapes.banana });
this.matter.add.sprite(360, 50, 'sheet', 'orange', { shape: shapes.orange });
this.matter.add.sprite(400, 250, 'sheet', 'cherries', { shape: shapes.cherries });
const shapeKeys = [ 'crate', 'banana', 'orange', 'cherries' ];
this.input.on('pointerdown', function (pointer)
{
const fruit = Phaser.Utils.Array.GetRandom(shapeKeys);
this.matter.add.image(pointer.x, pointer.y, 'sheet', fruit, { shape: shapes[fruit] });
}, this);
}
}
/*
* This example show how to load complex shapes created with PhysicsEditor (https://www.codeandweb.com/physicseditor)
*/
const config = {
type: Phaser.AUTO,
parent: 'phaser-example',
width: 600,
height: 800,
scene: Example,
physics: {
default: 'matter',
matter: {
debug: true
}
}
};
const game = new Phaser.Game(config);
Подготовка данных: загрузка атласа и форм
Для работы с кастомными формами необходимо подготовить два ресурса: графический атлас со спрайтами и JSON-файл с описанием полигонов для каждого из них. В методе preload мы загружаем оба файла.
this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
this.load.atlas('sheet', 'assets/physics/fruit-sprites.png', 'assets/physics/fruit-sprites.json');
this.load.json('shapes', 'assets/physics/fruit-shapes.json');
Первый вызов this.load.atlas загружает изображение-атлас (fruit-sprites.png) и файл с координатами кадров внутри него (fruit-sprites.json). Второй вызов this.load.json загружает файл fruit-shapes.json, сгенерированный в PhysicsEditor. Он содержит массив вершин для полигональной формы каждого спрайта, который мы будем использовать в качестве коллайдера.
Инициализация мира и создание статического тела
В методе create мы настраиваем физический мир и создаем статическую платформу (ground), используя загруженные формы.
this.matter.world.setBounds(0, 0, 600, 800);
const shapes = this.cache.json.get('shapes');
const ground = this.matter.add.sprite(0, 0, 'sheet', 'ground', { shape: shapes.ground });
this.matter.alignBody(ground, 300, 800, Phaser.Display.Align.BOTTOM_CENTER);
Сначала мы устанавливаем границы мира Matter.js. Затем получаем из кеша объект shapes с описанием всех полигонов. Ключевой момент — передача конфигурационного объекта { shape: shapes.ground } в метод this.matter.add.sprite. Параметр shape указывает движку использовать не стандартный прямоугольник, а полигональную форму с ключом ground из нашего JSON. Метод this.matter.alignBody позиционирует физическое тело платформы по центру нижней границы игрового поля.
Создание динамических тел со сложными формами
Теперь создадим несколько падающих объектов — ящик и фрукты. Для каждого из них также указывается своя уникальная форма из загруженного JSON.
this.matter.add.sprite(200, 50, 'sheet', 'crate', { shape: shapes.crate });
this.matter.add.sprite(250, 250, 'sheet', 'banana', { shape: shapes.banana });
this.matter.add.sprite(360, 50, 'sheet', 'orange', { shape: shapes.orange });
this.matter.add.sprite(400, 250, 'sheet', 'cherries', { shape: shapes.cherries });
Каждый вызов this.matter.add.sprite создает динамическое физическое тело. Обратите внимание, что в качестве текстуры (четвертый аргумент) и формы (ключ в объекте shapes) используются согласованные имена: 'crate', 'banana' и т.д. Это гарантирует, что визуальный спрайт и его физическое представление полностью совпадают.
Интерактивность: создание объектов по клику
Добавим интерактивности, позволяя игроку создавать новые фрукты в месте клика мышью.
const shapeKeys = [ 'crate', 'banana', 'orange', 'cherries' ];
this.input.on('pointerdown', function (pointer) {
const fruit = Phaser.Utils.Array.GetRandom(shapeKeys);
this.matter.add.image(pointer.x, pointer.y, 'sheet', fruit, { shape: shapes[fruit] });
}, this);
Мы создаем массив shapeKeys с ключами форм для случайного выбора. При событии pointerdown с помощью Phaser.Utils.Array.GetRandom выбирается случайный ключ. Затем в координатах клика (pointer.x, pointer.y) создается новый спрайт с физическим телом, использующим соответствующую форму из объекта shapes. Это демонстрирует, как динамически создавать объекты с заранее подготовленными сложными коллайдерами.
Настройка конфигурации игры и отладка
Для корректной работы примера необходима правильная конфигурация игры, в которой активирован физический движок Matter.js.
const config = {
type: Phaser.AUTO,
parent: 'phaser-example',
width: 600,
height: 800,
scene: Example,
physics: {
default: 'matter',
matter: {
debug: true
}
}
};
В блоке physics указывается default: 'matter'. Это ключевой параметр, который подключает нужный плагин. Внутри matter установлен флаг debug: true. При его включении поверх спрайтов отрисовываются контуры физических тел (полигональные формы), что невероятно полезно для отладки и проверки соответствия графики и коллайдера.
Что попробовать дальше
Использование внешних редакторов вроде PhysicsEditor для создания полигональных коллайдеров выводит физику вашей игры на новый уровень реализма. Этот метод незаменим для аркадных головоломок, симуляторов или любых проектов, где важна точность столкновений. Для экспериментов попробуйте: изменить плотность или упругость разных форм в конфиге Matter; создать составное тело из нескольких простых форм; анимировать спрайт, оставив его физическую форму неизменной.
