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

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

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

Живой запуск

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

Исходный код


class Example extends Phaser.Scene
{
    a = 0;
    graphics;
    point;
    circle;

    create ()
    {
        this.graphics = this.add.graphics({ lineStyle: { width: 2, color: 0x00ff00 }, fillStyle: { color: 0xff0000 }});

        this.circle = new Phaser.Geom.Circle(400, 300, 200);
        this.point = new Phaser.Geom.Rectangle(0, 0, 16, 16);
    }

    update ()
    {
        this.a += 0.01;

        if (this.a > Math.PI * 2)
        {
            this.a -= Math.PI * 2;
        }

        this.point.x = 400 - Math.cos(this.a) * 400;
        this.point.y = 300 - Math.sin(this.a * 2) * 300;

        this.graphics.clear();
        this.graphics.strokeCircleShape(this.circle);

        if (Phaser.Geom.Circle.ContainsPoint(this.circle, this.point))
        {
            this.graphics.fillStyle(0xff0000);
        }
        else
        {
            this.graphics.fillStyle(0x0000ff);
        }

        this.graphics.fillRect(this.point.x - 8, this.point.y - 8, this.point.width, this.point.height);
    }
}

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

const game = new Phaser.Game(config);

Подготовка сцены и объектов

В методе create() инициализируются основные объекты, которые будут использоваться для визуализации и расчетов.

Создается объект Graphics для отрисовки. Ему сразу задаются стили линии (зеленая) и заливки (красная), которые будут применяться по умолчанию.

Затем создаются две геометрические фигуры: 1. Phaser.Geom.Circle — круг с центром в точке (400, 300) и радиусом 200 пикселей. Это наша целевая зона. 2. Phaser.Geom.Rectangle — прямоугольник размером 16x16 пикселей. В контексте примера он представляет собой точку (его верхний левый угол) для проверки.

this.graphics = this.add.graphics({ lineStyle: { width: 2, color: 0x00ff00 }, fillStyle: { color: 0xff0000 }});

this.circle = new Phaser.Geom.Circle(400, 300, 200);
this.point = new Phaser.Geom.Rectangle(0, 0, 16, 16);

Анимация движения точки

В методе update(), который вызывается каждый кадр, реализуется движение нашей "точки" (прямоугольника) по сложной траектории.

Угол `a` увеличивается на 0.01 радиана каждый кадр, создавая непрерывную анимацию. Когда значение превышает полный круг (2π), оно сбрасывается, чтобы избежать переполнения.

Координаты точки рассчитываются с использованием тригонометрических функций Math.cos и Math.sin. Обратите внимание, что для координаты `yугол умножается на 2 (this.a * 2`), что создает более сложную, "восьмеркообразную" траекторию Лиссажу, а не просто движение по окружности.

this.a += 0.01;
if (this.a > Math.PI * 2)
{
    this.a -= Math.PI * 2;
}
this.point.x = 400 - Math.cos(this.a) * 400;
this.point.y = 300 - Math.sin(this.a * 2) * 300;

Очистка и отрисовка кадра

Перед каждой новой отрисовкой необходимо очистить холст Graphics от предыдущего кадра. Для этого используется метод clear().

После очистки отрисовывается контур нашего целевого круга с помощью метода strokeCircleShape(), который принимает объект Phaser.Geom.Circle.

this.graphics.clear();
this.graphics.strokeCircleShape(this.circle);

Ключевая проверка и визуальный ответ

Здесь происходит самое важное — проверка, находится ли текущая позиция точки внутри круга.

Для этого используется статический метод Phaser.Geom.Circle.ContainsPoint(). Он принимает два аргумента: объект круга и объект точки (или любой объект, имеющий свойства `xиy, как наш прямоугольникthis.point). Метод возвращаетtrueилиfalse`.

В зависимости от результата проверки, меняется цвет заливки у объекта Graphics. Если точка внутри круга — цвет красный (0xff0000), если снаружи — синий (0x0000ff).

Наконец, отрисовывается сама точка в виде залитого квадрата. Его центр позиционируется в координатах point.x и point.y.

if (Phaser.Geom.Circle.ContainsPoint(this.circle, this.point))
{
    this.graphics.fillStyle(0xff0000);
}
else
{
    this.graphics.fillStyle(0x0000ff);
}
this.graphics.fillRect(this.point.x - 8, this.point.y - 8, this.point.width, this.point.height);

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

Метод Phaser.Geom.Circle.ContainsPoint() предоставляет готовое, оптимизированное решение для проверки попадания точки в круг, избавляя разработчика от необходимости реализовывать формулу расстояния вручную. **Идеи для экспериментов:** 1. Замените Phaser.Geom.Rectangle на объект игрока (sprite) и проверяйте его центр. 2. Создайте массив кругов-ловушек и проверяйте попадание в любой из них. 3. Используйте результат проверки не только для смены цвета, но и для начисления очков, активации механизмов или нанесения урона.