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

Визуализация динамических форм — ключ к созданию гипнотических фонов, эффектов заклинаний или индикаторов загрузки. В этом примере мы не просто рисуем эллипс, а оживляем его, заставляя плавно трансформироваться по заданной траектории. Мы разберем, как использовать методы геометрического смещения `Phaser.Geom.Ellipse.OffsetPoint` и вращения вектора `Phaser.Math.Rotate` для создания плавной анимации спирали без единого спрайта или текстуры, используя только Canvas API через `Graphics`. Это мощный прием для procedural-графики, который не нагружает память текстурами и работает на чистой математике.

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

Живой запуск

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

Исходный код


class Example extends Phaser.Scene
{
    ellipse;
    point;
    step = 0.5;
    graphics;

    create ()
    {
        this.graphics = this.add.graphics({ fillStyle: { color: 0x00aaaa } });

        this.ellipse = new Phaser.Geom.Ellipse(380, 280, 20, 0);

        this.point = new Phaser.Math.Vector2(20, 0);
    }

    update ()
    {
        if (this.ellipse.y < 600)
        {
            this.graphics.fillEllipseShape(this.ellipse);

            Phaser.Geom.Ellipse.OffsetPoint(this.ellipse, this.point);

            Phaser.Math.Rotate(this.point, this.step);

            this.ellipse.width = this.point.x;
            this.ellipse.height = this.point.y;

            this.step *= 0.996;
        }
    }
}

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

const game = new Phaser.Game(config);

Сцена и объекты: готовим холст

В методе create() инициализируются основные объекты для отрисовки. Создается экземпляр Graphics — наш инструмент для рисования фигур напрямую на канвасе. Затем определяется эллипс с нулевой начальной высотой и точка-вектор, которая будет управлять его изменением.

create ()
{
    this.graphics = this.add.graphics({ fillStyle: { color: 0x00aaaa } });
    this.ellipse = new Phaser.Geom.Ellipse(380, 280, 20, 0);
    this.point = new Phaser.Math.Vector2(20, 0);
}

Сердце анимации: цикл update

Каждый кадр в update() эллипс рисуется на экране с текущими параметрами. После отрисовки его позиция смещается на значение вектора this.point с помощью статического метода Phaser.Geom.Ellipse.OffsetPoint. Это ключевой момент: эллипс не просто меняет размер, а движется в пространстве.

if (this.ellipse.y < 600)
{
    this.graphics.fillEllipseShape(this.ellipse);
    Phaser.Geom.Ellipse.OffsetPoint(this.ellipse, this.point);
}

Динамика формы: вращение и масштабирование

Чтобы траектория движения закручивалась, вектор this.point вращается на небольшой угол this.step с помощью Phaser.Math.Rotate. Затем ширина и высота эллипса обновляются значениями X и Y этого вектора, что создает эффект "раскручивания". Постепенное уменьшение угла шага (this.step *= 0.996) замедляет вращение, формируя плавное затухание спирали.

Phaser.Math.Rotate(this.point, this.step);
this.ellipse.width = this.point.x;
this.ellipse.height = this.point.y;
this.step *= 0.996;

Конфигурация игры: минимальный шаблон

Это стандартная конфигурация для запуска примера Phaser. Важно, что здесь используется type: Phaser.AUTO, что позволяет движку самому выбрать рендерер (WebGL или Canvas).

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

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

Вы освоили механизм procedural-анимации геометрических фигур, комбинируя смещение и вращение. Для экспериментов попробуйте изменить начальный цвет или стиль fillStyle, добавьте градиент, управляйте шагом this.step в зависимости от времени или ввода с клавиатуры. Можно создать несколько эллипсов с разными начальными точками для сложных паттернов или привязать анимацию к здоровью персонажа, где спираль будет визуальным индикатором.