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

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

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

Живой запуск

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

Исходный код


class Example extends Phaser.Scene
{
    create ()
    {
        const graphics = this.add.graphics();

        const line = new Phaser.Geom.Line(300, 200, 500, 400);
        const point = new Phaser.Math.Vector2(200, 100);

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

            point.x = Math.round(pointer.x / 10) * 10;
            point.y = Math.round(pointer.y / 10) * 10;

            redraw();
        });

        redraw();

        function redraw ()
        {
            graphics.clear();

            graphics.lineStyle(2, 0x00ff00);
            graphics.strokeLineShape(line);

            if (Phaser.Geom.Intersects.PointToLine(point, line))
            {
                graphics.fillStyle(0xff0000);
            }
            else
            {
                graphics.fillStyle(0xffff00);
            }

            graphics.fillPointShape(point, 5);
        }
    }
}

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

const game = new Phaser.Game(config);

Создание геометрических объектов

В основе примера лежат два ключевых объекта: линия и точка. Линия создаётся как экземпляр класса Phaser.Geom.Line, где конструктор принимает координаты начала (x1, y1) и конца (x2, y2). Точка представлена объектом Phaser.Math.Vector2, который удобен для математических операций.

const line = new Phaser.Geom.Line(300, 200, 500, 400);
const point = new Phaser.Math.Vector2(200, 100);

Обработка движения указателя

Для интерактивности пример отслеживает движение курсора мыши. Событие 'pointermove' привязывается к игровому вводу. Координаты точки обновляются в реальном времени, но с небольшой модификацией: они округляются до ближайшего значения, кратного 10. Это создаёт эффект "сетки" и облегчает визуальное восприятие. После каждого обновления вызывается функция перерисовки redraw().

this.input.on('pointermove', pointer => {
    point.x = Math.round(pointer.x / 10) * 10;
    point.y = Math.round(pointer.y / 10) * 10;
    redraw();
});

Проверка пересечения и визуализация

Сердце примера — функция redraw(). Она сначала очищает холст графики, затем отрисовывает линию зелёным цветом с помощью graphics.strokeLineShape(line). Далее происходит ключевая проверка: метод Phaser.Geom.Intersects.PointToLine(point, line) возвращает true, если точка лежит на отрезке линии, и false в противном случае. В зависимости от результата выбирается цвет заливки точки: красный для пересечения и жёлтый для его отсутствия. Точка отрисовывается с помощью graphics.fillPointShape(point, 5), где 5 — это её радиус.

function redraw ()
{
    graphics.clear();
    graphics.lineStyle(2, 0x00ff00);
    graphics.strokeLineShape(line);
    if (Phaser.Geom.Intersects.PointToLine(point, line))
    {
        graphics.fillStyle(0xff0000);
    }
    else
    {
        graphics.fillStyle(0xffff00);
    }
    graphics.fillPointShape(point, 5);
}

Настройка игры и запуск сцены

Пример завершается стандартной для Phaser конфигурацией игры. В объекте config задаются размеры холста, тип рендерера, родительский элемент в DOM и класс сцены, в которой определена вся логика. Создание экземпляра Phaser.Game с этой конфигурацией запускает выполнение кода.

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

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

Метод Phaser.Geom.Intersects.PointToLine предоставляет простой и производительный способ проверки принадлежности точки отрезку. Это полезно не только для визуальных демонстраций, но и для игровой логики. Попробуйте использовать этот подход для создания невидимых путей, по которым должен двигаться персонаж, для проверки попадания выстрела в линейный барьер или для реализации кастомных интерфейсов с выбором опций вдоль линии. Экспериментируйте, добавляя несколько линий и меняя их параметры динамически.