О чем этот пример
При разработке игр часто возникает необходимость проверять геометрическое совпадение фигур — для определения столкновений, активации зон или визуального выделения объектов. Встроенный метод `Phaser.Geom.Triangle.Equals` предоставляет точный и производительный способ сравнения двух треугольников. В этой статье мы разберём живой пример, который показывает, как использовать этот метод для интерактивного сравнения треугольников на холсте, и объясним, как можно адаптировать этот подход для решения практических задач в ваших проектах.
Версия Phaser: код и демо в этой статье рассчитаны на Phaser 3.90.0.
Живой запуск
Ниже встроен рабочий билд примера. Оригинальный источник: GitHub.
Исходный код
class Example extends Phaser.Scene
{
create ()
{
const graphics = this.add.graphics();
const triangles = [];
for (let x = 0; x < 8; x++)
{
for (let y = 0; y < 6; y++)
{
const x1 = Phaser.Math.Between(4, 5) * 10 + x * 100;
const y3 = Phaser.Math.Between(8, 9) * 10 + y * 100;
const triangle = new Phaser.Geom.Triangle(
x1, 10 + y * 100,
10 + x * 100, 90 + y * 100,
90 + x * 100, y3);
triangles.push(triangle);
}
}
const pointerTriangle = new Phaser.Geom.Triangle(50, 10, 10, 90, 90, 90);
this.input.on('pointermove', pointer =>
{
const x = Math.floor(pointer.x / 100);
const y = Math.floor(pointer.y / 100);
pointerTriangle.x1 = 50 + x * 100;
pointerTriangle.y1 = 10 + y * 100;
pointerTriangle.x2 = 10 + x * 100;
pointerTriangle.y2 = 90 + y * 100;
pointerTriangle.x3 = 90 + x * 100;
pointerTriangle.y3 = 90 + y * 100;
redraw();
});
redraw();
function redraw ()
{
graphics.clear();
graphics.lineStyle(2, 0xaaaa00);
let strokeRed = false;
for (let i = 0; i < triangles.length; i++)
{
graphics.strokeTriangleShape(triangles[i]);
strokeRed = strokeRed || Phaser.Geom.Triangle.Equals(pointerTriangle, triangles[i]);
}
if (strokeRed)
{
graphics.lineStyle(5, 0xaa0000);
}
else
{
graphics.lineStyle(5, 0x0000aa);
}
graphics.strokeTriangleShape(pointerTriangle);
}
}
}
const config = {
width: 800,
height: 600,
type: Phaser.AUTO,
parent: 'phaser-example',
scene: Example
};
const game = new Phaser.Game(config);
Подготовка сцены и создание массива треугольников
В примере создаётся игровая сцена, на которой мы будем рисовать и сравнивать треугольники. Первым делом инициализируется объект graphics для отрисовки примитивов.
Затем в двойном цикле формируется массив из 48 треугольников (triangles). Они располагаются в сетке 8x6. Координаты вершин каждого треугольника вычисляются с небольшим случайным смещением с помощью Phaser.Math.Between, что делает демонстрацию более наглядной — треугольники не идеально выровнены.
const graphics = this.add.graphics();
const triangles = [];
for (let x = 0; x < 8; x++)
{
for (let y = 0; y < 6; y++)
{
const x1 = Phaser.Math.Between(4, 5) * 10 + x * 100;
const y3 = Phaser.Math.Between(8, 9) * 10 + y * 100;
const triangle = new Phaser.Geom.Triangle(
x1, 10 + y * 100,
10 + x * 100, 90 + y * 100,
90 + x * 100, y3);
triangles.push(triangle);
}
}
Создание управляемого треугольника и обработка ввода
Создаётся треугольник-курсор (pointerTriangle), который будет следовать за указателем мыши. Изначально он задаётся в координатах первой ячейки сетки.
На событие pointermove вешается обработчик. Он вычисляет, в какую ячейку сетки попал курсор, и пересчитывает координаты pointerTriangle, "привязывая" его к этой ячейке. После обновления позиции вызывается функция redraw() для перерисовки всего холста.
const pointerTriangle = new Phaser.Geom.Triangle(50, 10, 10, 90, 90, 90);
this.input.on('pointermove', pointer =>
{
const x = Math.floor(pointer.x / 100);
const y = Math.floor(pointer.y / 100);
pointerTriangle.x1 = 50 + x * 100;
pointerTriangle.y1 = 10 + y * 100;
pointerTriangle.x2 = 10 + x * 100;
pointerTriangle.y2 = 90 + y * 100;
pointerTriangle.x3 = 90 + x * 100;
pointerTriangle.y3 = 90 + y * 100;
redraw();
});
Логика сравнения и визуализация в функции redraw
Функция redraw() — сердце примера. Она очищает холст и заново рисует все треугольники. Ключевой момент происходит в цикле перебора массива triangles.
Для каждого треугольника из массива вызывается метод Phaser.Geom.Triangle.Equals, который сравнивает его с текущим положением pointerTriangle. Метод возвращает true только если все три вершины треугольников попарно равны (имеют одинаковые координаты `xиy`).
Флаг strokeRed становится true, если хотя бы один треугольник в массиве совпал с курсорным. В зависимости от этого флага меняется стиль линии (толщина и цвет) для отрисовки самого pointerTriangle. Это даёт мгновенную визуальную обратную связь.
function redraw ()
{
graphics.clear();
graphics.lineStyle(2, 0xaaaa00);
let strokeRed = false;
for (let i = 0; i < triangles.length; i++)
{
graphics.strokeTriangleShape(triangles[i]);
strokeRed = strokeRed || Phaser.Geom.Triangle.Equals(pointerTriangle, triangles[i]);
}
if (strokeRed)
{
graphics.lineStyle(5, 0xaa0000);
}
else
{
graphics.lineStyle(5, 0x0000aa);
}
graphics.strokeTriangleShape(pointerTriangle);
}
Важные детали работы метода Equals
Метод Phaser.Geom.Triangle.Equals выполняет точное сравнение координат. Это важно понимать: треугольник со вершинами (0,0, 10,0, 0,10) не будет считаться равным треугольнику (0,0, 0,10, 10,0), хотя они конгруэнтны — важен порядок вершин. В данном примере совпадение возможно, потому что оба треугольника создаются по одинаковому шаблону для одной ячейки сетки.
Для сравнения треугольников с учётом погрешности (например, при проверке столкновений) в Phaser существуют другие методы, например, Phaser.Geom.Triangle.Contains. Метод Equals же идеален для случаев, когда нужно проверить, ссылаются ли две переменные на один и тот же геометрический объект или на объекты с идентичными координатами.
Что попробовать дальше
Метод Phaser.Geom.Triangle.Equals — это простой и эффективный инструмент для точного сравнения треугольников. Показанный пример можно адаптировать для систем выделения объектов, проверки правильности сборки пазла или активации триггеров в игре. Для экспериментов попробуйте изменить логику: сравнивайте pointerTriangle не со всеми треугольниками, а только с ближайшим, используя Phaser.Geom.Triangle.Center, или добавьте проверку на приблизительное равенство с заданной дельтой.
