О чем этот пример
В игровой разработке часто нужно реагировать на взаимодействие пользователя с объектами. Например, подсветить объект при наведении курсора. Phaser с физическим движком Matter.js предоставляет для этого простой и эффективный инструмент — метод `containsPoint`. Эта статья покажет, как использовать его для обнаружения точки внутри сложных полигональных тел и динамического изменения их внешнего вида, что полезно для создания интерактивных интерфейсов, пазлов или тактических карт.
Версия Phaser: код и демо в этой статье рассчитаны на Phaser 3.90.0.
Живой запуск
Ниже встроен рабочий билд примера. Оригинальный источник: GitHub.
Исходный код
class Example extends Phaser.Scene
{
constructor()
{
super();
}
create()
{
const body1 = this.matter.add.polygon(100, 300, 8, 70, { isStatic: true });
const body2 = this.matter.add.fromVertices(300, 300, '50 0 63 38 100 38 69 59 82 100 50 75 18 100 31 59 0 38 37 38', {}, true);
const body3 = this.matter.add.polygon(500, 300, 3, 60);
const body4 = this.matter.add.rectangle(700, 300, 48, 256);
const fillOver = 0xff0000;
const strokeOver = 0xffff00;
const lineThicknessOver = 4;
const bodies = [ body1, body2, body3, body4 ];
this.input.on('pointermove', function (pointer) {
const x = pointer.worldX;
const y = pointer.worldY;
for (let i = 0; i < bodies.length; i++)
{
const body = bodies[i];
if (this.matter.containsPoint(body, x, y))
{
this.matter.world.setBodyRenderStyle(body, fillOver, strokeOver, lineThicknessOver);
}
else
{
this.matter.world.setBodyRenderStyle(body);
}
}
}, this);
}
}
const config = {
type: Phaser.AUTO,
width: 800,
height: 600,
backgroundColor: '#4d4d4d',
parent: 'phaser-example',
physics: {
default: 'matter',
matter: {
enableSleeping: false,
gravity: {
y: 0
},
debug: {}
}
},
scene: Example
};
const game = new Phaser.Game(config);
Создание тел для тестирования
В примере создаются четыре статических и динамических тела разной формы с помощью фабричных методов модуля matter. Это демонстрирует универсальность подхода: метод containsPoint работает с любым типом тела, созданного в Matter.js.
const body1 = this.matter.add.polygon(100, 300, 8, 70, { isStatic: true });
const body2 = this.matter.add.fromVertices(300, 300, '50 0 63 38 100 38 69 59 82 100 50 75 18 100 31 59 0 38 37 38', {}, true);
const body3 = this.matter.add.polygon(500, 300, 3, 60);
const body4 = this.matter.add.rectangle(700, 300, 48, 256);
Обработка движения курсора
Основная логика привязана к событию pointermove. При каждом движении мыши или касании мы получаем мировые координаты курсора. Эти координаты (pointer.worldX, pointer.worldY) будут проверяться на пересечение с телами.
this.input.on('pointermove', function (pointer) {
const x = pointer.worldX;
const y = pointer.worldY;
// ... логика проверки
}, this);
Проверка точки внутри тела с помощью `containsPoint`
Ключевой метод this.matter.containsPoint(body, x, y) возвращает true, если переданные координаты находятся внутри границ физического тела. В примере мы перебираем массив всех созданных тел и для каждого выполняем эту проверку.
for (let i = 0; i < bodies.length; i++)
{
const body = bodies[i];
if (this.matter.containsPoint(body, x, y))
{
// Точка внутри тела
}
else
{
// Точка снаружи тела
}
}
Визуальная обратная связь: `setBodyRenderStyle`
Чтобы визуализировать результат проверки, используется метод this.matter.world.setBodyRenderStyle(). Если точка внутри тела, телу присваивается стиль подсветки (цвет заливки, цвет обводки, толщина линии). Если точка снаружи, метод вызывается без аргументов, что сбрасывает стиль отрисовки тела к значениям по умолчанию из конфигурации debug.
if (this.matter.containsPoint(body, x, y))
{
this.matter.world.setBodyRenderStyle(body, fillOver, strokeOver, lineThicknessOver);
}
else
{
this.matter.world.setBodyRenderStyle(body);
}
Настройка физического движка Matter
Для работы примера критически важна правильная конфигурация движка. Включен движок matter, отключена гравитация по оси Y (y: 0), чтобы тела не падали, и активирован отладочный рендеринг (debug: {}), который позволяет видеть контуры тел. Без debug метод setBodyRenderStyle не будет иметь визуального эффекта.
physics: {
default: 'matter',
matter: {
enableSleeping: false,
gravity: { y: 0 },
debug: {}
}
}
Что попробовать дальше
Метод containsPoint — это мощный и точный способ проверки попадания точки в физическое тело любой сложности. Он идеально подходит для реализации подсветки, выбора объектов или триггеров активации в играх. Для экспериментов попробуйте: изменить условие проверки так, чтобы тело подсвечивалось только при клике; применить эту логику к динамическим движущимся телам; или комбинировать ее с другими методами Matter.js, например, для выпуска луча (raycast) из точки наведения.
