О чем этот пример

В играх часто требуется определять пересечение сложных форм. Встроенный модуль геометрии Phaser позволяет эффективно проверять столкновения между различными фигурами, включая треугольники. Эта статья разбирает практический пример отслеживания пересечения двух вращающихся и перемещающихся треугольников, что может быть полезно для создания кастомных хитбоксов, зон поражения или геометрических головоломок.

Версия Phaser: код и демо в этой статье рассчитаны на Phaser 3.90.0.

Живой запуск

Ниже встроен рабочий билд примера. Оригинальный источник: GitHub.

Исходный код


class Example extends Phaser.Scene
{
    graphics;
    triangleB;
    triangle;

    create ()
    {
        this.graphics = this.add.graphics();

        // triangle = new Phaser.Geom.Triangle.BuildEquilateral(400, 320, 140);
        this.triangle = new Phaser.Geom.Triangle.BuildEquilateral(400, 320, 40);

        this.triangleB = new Phaser.Geom.Triangle(400, 200, 300, 300, 500, 300);

        this.graphics.lineStyle(2, 0x00ff00);
        this.graphics.strokeTriangleShape(this.triangleB);
        this.graphics.lineStyle(2, 0xffff00);
        this.graphics.strokeTriangleShape(this.triangle);

        this.input.on('pointermove', pointer =>
        {

            Phaser.Geom.Triangle.CenterOn(this.triangle, pointer.x, pointer.y);

        });
    }

    update ()
    {
        Phaser.Geom.Triangle.Rotate(this.triangleB, 0.02);

        this.graphics.clear();
        this.graphics.lineStyle(2, 0x00ff00);
        this.graphics.strokeTriangleShape(this.triangleB);

        if (Phaser.Geom.Intersects.TriangleToTriangle(this.triangle, this.triangleB))
        {
            this.graphics.lineStyle(2, 0xff0000);
        }
        else
        {
            this.graphics.lineStyle(2, 0xffff00);
        }

        this.graphics.strokeTriangleShape(this.triangle);
    }
}

const config = {
    width: 800,
    height: 600,
    type: Phaser.AUTO,
    parent: 'phaser-example',
    scene: Example
};

const game = new Phaser.Game(config);

Инициализация сцены и создание треугольников

В методе create() сцены происходит подготовка графики и создание геометрических объектов. Сначала мы создаем экземпляр Graphics для отрисовки линий.

Затем определяем два треугольника. Первый (this.triangle) создается с помощью фабричного метода Phaser.Geom.Triangle.BuildEquilateral, который строит равносторонний треугольник по центру и длине стороны. Второй треугольник (this.triangleB) создается явным указанием координат его трех вершин.

this.graphics = this.add.graphics();
this.triangle = new Phaser.Geom.Triangle.BuildEquilateral(400, 320, 40);
this.triangleB = new Phaser.Geom.Triangle(400, 200, 300, 300, 500, 300);

Сразу после создания треугольники отрисовываются на экране с разным цветом контура.

this.graphics.lineStyle(2, 0x00ff00);
this.graphics.strokeTriangleShape(this.triangleB);
this.graphics.lineStyle(2, 0xffff00);
this.graphics.strokeTriangleShape(this.triangle);

Интерактивность: движение треугольника за курсором

Чтобы сделать пример наглядным, первый треугольник привязан к движению указателя мыши. Для этого используется обработчик события 'pointermove'. При каждом движении мыши позиция треугольника this.triangle центрируется на координатах курсора с помощью статического метода Phaser.Geom.Triangle.CenterOn. Этот метод не изменяет форму или ориентацию треугольника, а лишь перемещает его целиком.

this.input.on('pointermove', pointer => {
    Phaser.Geom.Triangle.CenterOn(this.triangle, pointer.x, pointer.y);
});

Таким образом, пользователь может водить одним треугольником по экрану, проверяя его пересечение со вторым.

Анимация и проверка пересечений в update()

Основная логика обновления кадра находится в методе update(). Здесь происходят три ключевые вещи: анимация, проверка столкновений и перерисовка.

Сначала второй треугольник (this.triangleB) непрерывно вращается вокруг своего центра. Это делает пример динамичным.

Phaser.Geom.Triangle.Rotate(this.triangleB, 0.02);

Перед отрисовкой нового кадра необходимо очистить старое изображение.

this.graphics.clear();

Затем снова отрисовывается неподвижный (но вращающийся) треугольник this.triangleB.

this.graphics.lineStyle(2, 0x00ff00);
this.graphics.strokeTriangleShape(this.triangleB);

Сердце примера: функция TriangleToTriangle

Самая важная строка кода – это вызов функции проверки пересечения. Статический метод Phaser.Geom.Intersects.TriangleToTriangle принимает два объекта треугольника и возвращает true, если они пересекаются (или соприкасаются), и false в противном случае.

if (Phaser.Geom.Intersects.TriangleToTriangle(this.triangle, this.triangleB))

В зависимости от результата проверки, меняется цвет контура для перемещаемого треугольника (this.triangle). При пересечении он становится красным, в остальное время – желтым. Это дает мгновенную визуальную обратную связь.

if (Phaser.Geom.Intersects.TriangleToTriangle(this.triangle, this.triangleB))
{
    this.graphics.lineStyle(2, 0xff0000);
}
else
{
    this.graphics.lineStyle(2, 0xffff00);
}
this.graphics.strokeTriangleShape(this.triangle);

Что попробовать дальше

Пример демонстрирует мощь и простоту геометрического модуля Phaser. Функция TriangleToTriangle избавляет разработчика от необходимости реализовывать сложные математические алгоритмы проверки пересечений. Для экспериментов попробуйте изменить форму треугольников на произвольную, добавить больше фигур и проверять пересечения между ними или использовать результат проверки не только для смены цвета, но и для игровой логики – например, нанесения урона или активации механизма.