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

Градиенты в Phaser 3 — это мощный инструмент визуализации, который часто используется для создания динамических фонов, эффектов освещения и абстрактных анимаций. Однако тонкости работы со смещением (`offset`) и формой (`shape`) могут привести к неожиданным и интересным артефактам, которые разработчики могут превратить в сознательные художественные приёмы. Эта статья разбирает пример кода, демонстрирующий, как разные режимы градиента (`BILINEAR`, `CONIC_SYMMETRIC`, `CONIC_ASYMMETRIC`) реагируют на анимированное смещение, и показывает, как управлять направлением конического градиента динамически.

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

Живой запуск

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

Исходный код


class Example extends Phaser.Scene
{
    create ()
    {
        // Bilinear offset is mirrored.
        const bilinear = this.add.gradient({
            repeatMode: 2, // SAWTOOTH
            shapeMode: 1, // BILINEAR
            start: { x: 0.5, y: 0.5 },
            shape: { x: 0.1, y: 0 },
            bands: {
                colorStart: 0xcccccc,
                colorEnd: 0x8899cc,
            }
        }, 640, 360, 1280, 720);
        this.bilinear = bilinear;

        // Symmetric conic offset is kaleidoscopic,
        // as the offset shifts the symmetry point.
        const conicSymmetric = this.add.gradient({
            repeatMode: 2, // SAWTOOTH
            shapeMode: 3, // CONIC_SYMMETRIC
            start: { x: 0.5, y: 0.5 },
            shape: { x: 1, y: 0 },
            bands: {
                colorStart: 0xff8844,
                colorEnd: 0x8844ff,
                colorSpace: 1
            }
        }, 320, 256, 384, 384);
        this.conicSymmetric = conicSymmetric;
        Phaser.Actions.AddMaskShape(conicSymmetric, { useInternal: true, region: { x: 0, y: 0, width: 384, height: 384 } });

        // Asymmetric conic is actually fine.
        const conicAsymmetric = this.add.gradient({
            repeatMode: 2, // SAWTOOTH
            shapeMode: 4, // CONIC_ASYMMETRIC
            start: { x: 0.5, y: 0.5 },
            shape: { x: 1, y: 0 },
            bands: {
                colorStart: 0x44ff88,
                colorEnd: 0xff8844,
                colorSpace: 1
            }
        }, 960, 256, 384, 384);
        this.conicAsymmetric = conicAsymmetric;
        Phaser.Actions.AddMaskShape(conicAsymmetric, { useInternal: true, region: { x: 0, y: 0, width: 384, height: 384 } });

        // You can instead reshape a symmetric conic gradient.
        // See `update`.
        const conicReshape = this.add.gradient({
            repeatMode: 2, // SAWTOOTH
            shapeMode: 3, // CONIC_SYMMETRIC
            start: { x: 0.5, y: 0.5 },
            shape: { x: 1, y: 0 },
            bands: {
                colorStart: 0xffcc44,
                colorEnd: 0x4488ff,
                colorSpace: 1
            }
        }, 640, 512, 384, 384);
        this.conicReshape = conicReshape;
        Phaser.Actions.AddMaskShape(conicReshape, { useInternal: true, region: { x: 0, y: 0, width: 384, height: 384 } });
    }

    update (time)
    {
        this.bilinear.offset = time / 1000;
        this.conicSymmetric.offset = time / 1000;
        this.conicAsymmetric.offset = time / 1000;

        // Reshape symmetric cone gradient to point in a different direction.
        // Shape is a Vector2 so supports many useful methods.
        this.conicReshape.shape.setAngle(time * Math.PI / 1000);
    }
}

const config = {
    type: Phaser.WEBGL,
    width: 1280,
    height: 720,
    backgroundColor: '#2d2d2d',
    parent: 'phaser-example',
    scene: Example
};

const game = new Phaser.Game(config);

Основа: создание градиента с помощью `this.add.gradient`

Основной метод для создания градиентного игрового объекта — this.add.gradient. Он принимает объект конфигурации, позицию (x, y) и размеры (width, height). Ключевые параметры конфигурации: - repeatMode: режим повторения. В примере используется `2(Phaser.Gradient.GradientRepeatMode.SAWTOOTH`). - shapeMode: определяет математическую форму градиента. - start: точка начала градиента в нормализованных координатах (от 0 до 1). - shape: вектор, задающий направление или форму градиента. - bands: объект с настройками цветовых полос (colorStart, colorEnd, colorSpace).

Создадим базовый билинейный градиент:

const bilinear = this.add.gradient({
    repeatMode: 2, // SAWTOOTH
    shapeMode: 1, // BILINEAR
    start: { x: 0.5, y: 0.5 },
    shape: { x: 0.1, y: 0 },
    bands: {
        colorStart: 0xcccccc,
        colorEnd: 0x8899cc,
    }
}, 640, 360, 1280, 720);

Эффект зеркального смещения в билинейном градиенте

В примере свойству bilinear.offset в методе update присваивается значение, зависящее от времени. Это заставляет текстуру градиента «прокручиваться». Однако из-за особенностей режима SAWTOOTH и формы BILINEAR смещение приводит к зеркальному эффекту, а не к плавному линейному сдвигу. Градиент как бы отражается от своих границ. Это поведение встроено в шейдер, который рассчитывает цвет для этой конкретной формы (shapeMode).

Код анимации смещения:

this.bilinear.offset = time / 1000;

Здесь time — это время в миллисекундах, передаваемое в update. Деление на 1000 замедляет анимацию, делая её видимой глазу.

Калидоскопический эффект в симметричном коническом градиенте

Симметричный конический градиент (CONIC_SYMMETRIC) создаёт узор, симметричный относительно точки начала (start). Когда мы применяем смещение (offset), эта точка симметрии сдвигается, что приводит к калейдоскопическому, вращающемуся эффекту. В примере градиент обрезается маской с помощью Phaser.Actions.AddMaskShape для создания аккуратного квадратного вида.

Создание и маскирование градиента:

const conicSymmetric = this.add.gradient({
    repeatMode: 2,
    shapeMode: 3, // CONIC_SYMMETRIC
    start: { x: 0.5, y: 0.5 },
    shape: { x: 1, y: 0 },
    bands: {
        colorStart: 0xff8844,
        colorEnd: 0x8844ff,
        colorSpace: 1
    }
}, 320, 256, 384, 384);
Phaser.Actions.AddMaskShape(conicSymmetric, { useInternal: true, region: { x: 0, y: 0, width: 384, height: 384 } });

Анимация смещения выполняется аналогично: this.conicSymmetric.offset = time / 1000;.

Стабильность асимметричного конического градиента

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

Код создания идентичен, за исключением shapeMode: 4:

shapeMode: 4, // CONIC_ASYMMETRIC

Динамическое изменение направления градиента через свойство `shape`

Свойство shape градиента — это объект Phaser.Math.Vector2. Это позволяет не только задать начальное направление, но и динамически менять его, используя методы вектора. В примере для объекта conicReshape в update вызывается this.conicReshape.shape.setAngle(...). Это вращает вектор направления градиента, заставляя весь конический узор плавно поворачиваться вокруг точки start.

this.conicReshape.shape.setAngle(time * Math.PI / 1000);

Метод setAngle устанавливает угол вектора в радианах. Умножение time на Math.PI / 1000 создаёт медленное непрерывное вращение. Это более контролируемый способ анимации, чем изменение offset, и он не вызывает нежелательных артефактов в симметричном режиме.

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

Смещение и форма градиентов в Phaser 3 открывают пространство для экспериментов. Зеркальный эффект BILINEAR и калейдоскопический CONIC_SYMMETRIC можно использовать для создания психоделических фонов или эффектов искажения. Для плавных вращений лучше подходит CONIC_ASYMMETRIC или прямое управление вектором shape. Попробуйте комбинировать анимацию offset и shape, применять разные colorSpace для нелинейных цветовых переходов или накладывать несколько градиентов с режимами наложения (blendMode) для создания сложных визуальных текстур.