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

Работа с графикой — это мощный инструмент для создания атмосферы и визуальных эффектов в вашей игре без использования внешних ассетов. Phaser предоставляет гибкий API для программной отрисовки примитивов, который можно использовать для генерации фонов, спецэффектов или динамических UI-элементов. В этой статье мы разберем, как создать простую, но завораживающую анимацию из концентрических кругов, которая отлично подойдет для фона меню, психоделического эффекта или индикатора загрузки. Вы научитесь управлять объектами `Graphics`, настраивать их стили и анимировать.

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

Живой запуск

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

Исходный код


class Example extends Phaser.Scene
{
    graphics2;
    graphics1;
    t = 0;

    create ()
    {
        this.graphics2 = this.add.graphics({x: -16, y: 0}).lineStyle(28, 0x00ffff, 0.8);
        this.graphics1 = this.add.graphics().lineStyle(28, 0x0000ff, 0.8);

        //  Create the circles

        let radius1 = 64;
        let radius2 = 32;

        for (let i = 0; i < 8; i++)
        {
            this.graphics1.strokeCircle(400, 300, radius1);
            this.graphics2.strokeCircle(400, 300, radius2);

            radius1 += 64;
            radius2 += 64;
        }

    }

    update ()
    {
        this.t += 0.1;

        this.graphics1.x += Math.sin(this.t) * 2;
        this.graphics1.y += Math.cos(this.t) * 2;

        this.graphics2.x += Math.sin(this.t) * 3;
        this.graphics2.y += Math.cos(this.t) * 3;

    }
}

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

const game = new Phaser.Game(config);

Инициализация графических объектов

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

Ключевой момент — это настройка стиля линии с помощью метода .lineStyle(). Первый аргумент — толщина линии в пикселях, второй — цвет в шестнадцатеричном формате, третий — альфа-канал (прозрачность).

Обратите внимание, что второму объекту graphics2 при создании сразу задается смещение по оси X. Это смещение применяется ко всем фигурам, которые будут в него нарисованы, что создает эффект "сдвинутого" слоя.

this.graphics2 = this.add.graphics({x: -16, y: 0}).lineStyle(28, 0x00ffff, 0.8);
this.graphics1 = this.add.graphics().lineStyle(28, 0x0000ff, 0.8);

Отрисовка концентрических кругов

Следующий шаг — наполнение созданных объектов фигурами. Мы используем цикл for, чтобы нарисовать несколько окружностей с увеличивающимся радиусом.

Метод .strokeCircle(x, y, radius) рисует только контур (обводку) круга в соответствии с установленным ранее стилем линии. Центры всех кругов для одного объекта Graphics имеют одинаковые координаты (400, 300), но разные радиусы, что и создает набор концентрических окружностей.

Важно понимать, что graphics1 и graphics2 — это два независимых слоя, каждый со своим набором кругов. Их визуальное перекрытие и даст итоговый сложный узор.

let radius1 = 64;
let radius2 = 32;

for (let i = 0; i < 8; i++)
{
    this.graphics1.strokeCircle(400, 300, radius1);
    this.graphics2.strokeCircle(400, 300, radius2);

    radius1 += 64;
    radius2 += 64;
}

Анимация и движение слоев

Вся магия происходит в методе update(), который вызывается каждый кадр. Мы анимируем не отдельные круги, а целиком графические объекты, перемещая их в пространстве сцены.

Для плавного циклического движения используется тригонометрическая функция Math.sin() и Math.cos() от постоянно увеличивающейся переменной this.t. Умножение на разные коэффициенты (2 и 3) задает разную скорость и траекторию движения для каждого слоя.

Изменяя свойства .x и .y объектов graphics1 и graphics2, мы сдвигаем все нарисованные в них круги одновременно. Это эффективно с точки зрения производительности, так как движок перерисовывает всего два объекта, а не шестнадцать отдельных кругов.

this.t += 0.1;

this.graphics1.x += Math.sin(this.t) * 2;
this.graphics1.y += Math.cos(this.t) * 2;

this.graphics2.x += Math.sin(this.t) * 3;
this.graphics2.y += Math.cos(this.t) * 3;

Конфигурация игры и запуск

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

Создание экземпляра игры new Phaser.Game(config) инициализирует движок и запускает сцену, вызывая ее методы create() и затем update() в игровом цикле.

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

const game = new Phaser.Game(config);

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

Вы создали динамический визуальный эффект, управляя всего двумя объектами Graphics. Это демонстрирует мощь программной графики. Для экспериментов попробуйте: изменить цвета и прозрачность в lineStyle; добавить третий или четвертый слой кругов; заменить синусоидальное движение на линейное или хаотичное; использовать метод .fillCircle() для залитых кругов; менять толщину линии в зависимости от радиуса внутри цикла. Это основа для создания собственных уникальных фоновых анимаций и эффектов.