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

Создание плавной анимации геометрических фигур — мощный инструмент для визуальных эффектов в играх. Этот пример показывает, как можно в реальном времени генерировать и визуализировать сложные полигональные формы, например, для магических заклинаний, нестандартных интерфейсов или фоновых анимаций. Мы разберем, как использовать класс `Phaser.Geom.Polygon` и его ключевой метод `setTo()` для динамического обновления фигуры на основе математических формул. Вы научитесь превращать простые математические выражения в захватывающие визуальные паттерны.

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

Живой запуск

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

Исходный код


class Example extends Phaser.Scene
{
    graphics;
    angle = 0;
    radius = 100;
    points;
    polygon;

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

        this.polygon = new Phaser.Geom.Polygon();

        this.points = [];
    }

    update ()
    {
        if (this.angle <= Math.PI * 2)
        {
            this.angle += Math.PI / 30;
            const leafSize = 150 * Math.sin((this.angle * 2) % Math.PI);

            this.points.push(400 + Math.cos(this.angle) * (this.radius + leafSize));
            this.points.push(300 + Math.sin(this.angle) * (this.radius + leafSize));

            this.polygon.setTo(this.points);

            this.graphics.clear();

            this.graphics.strokePoints(this.polygon.points);
        }
    }
}

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

const game = new Phaser.Game(config);

Инициализация: Подготовка холста и объектов

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

this.graphics = this.add.graphics({ lineStyle: { width: 2, color: 0xaa6622 } });
this.polygon = new Phaser.Geom.Polygon();
this.points = [];

Объект this.graphics — это наш инструмент для отрисовки. Мы задаем ему стиль линии: толщину 2 пикселя и цвет (шестнадцатеричный код 0xaa6622). Phaser.Geom.Polygon — это геометрический объект, представляющий многоугольник. Изначально он пуст. Массив this.points будет хранить последовательность координат (x, y) для вершин нашего полигона.

Магия в update(): Генерация точек по формуле

Сердце анимации находится в методе update(), который вызывается на каждом кадре. Пока угол не превысит полный круг (2π), мы добавляем новую точку.

if (this.angle <= Math.PI * 2)
{
    this.angle += Math.PI / 30;
    const leafSize = 150 * Math.sin((this.angle * 2) % Math.PI);

    this.points.push(400 + Math.cos(this.angle) * (this.radius + leafSize));
    this.points.push(300 + Math.sin(this.angle) * (this.radius + leafSize));

Каждый шаг увеличивает угол. Переменная leafSize создает осцилляцию с двойной частотой, используя Math.sin. Это создает "лепестковый" эффект. Далее в массив points последовательно добавляются координаты X и Y. Формула 400 + Math.cos(angle) * (radius + leafSize) рассчитывает позицию точки на основе центра (400, 300), базового радиуса и динамического смещения leafSize.

Ключевой метод: setTo() и перерисовка

После добавления новых координат в массив, необходимо сообщить полигону о его новых границах. Именно для этого и существует метод setTo().

this.polygon.setTo(this.points);
this.graphics.clear();
this.graphics.strokePoints(this.polygon.points);

Метод setTo() полностью перезаписывает вершины полигона, принимая плоский массив чисел [x1, y1, x2, y2, ...]. После обновления геометрии мы очищаем предыдущий кадр с помощью clear() и рисуем новый контур полигона методом strokePoints(), который принимает массив объектов точек из polygon.points. Без вызова setTo() полигон оставался бы пустым, и отрисовки бы не происходило.

Сборка сцены: Конфигурация игры

Весь пример завершается стандартной для Phaser 3 конфигурацией игры, которая указывает размеры холста и корневой класс сцены.

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

const game = new Phaser.Game(config);

Этот блок кода создает экземпляр игры Phaser. Параметр scene: Example указывает, что наш класс Example будет использоваться в качестве основной сцены. Размер игрового поля устанавливается в 800x600 пикселей.

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

Метод setTo() класса Phaser.Geom.Polygon — это прямой способ динамического управления формой. Вы можете экспериментировать, меняя формулу для leafSize — попробуйте использовать Math.cos вместо sin или добавить больше множителей к углу. Также интересно изменять базовый radius со временем или использовать другие примитивы Graphics, например fillPoints(), для заливки фигуры цветом. Это открывает двери к созданию процедурных анимаций для ауры персонажей, анимированных порталов или уникальных траекторий движения.