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

Цвет — один из ключевых инструментов для создания атмосферы и визуального стиля игры. Phaser предоставляет мощный метод `setTint` для тонирования спрайтов, но многие разработчики используют его лишь для однородной заливки. Этот пример раскрывает продвинутую технику: создание плавных вертикальных градиентов (растров) с помощью тонирования отдельных углов спрайта. Освоив этот приём, вы сможете динамически окрашивать интерфейсы, создавать сложные световые эффекты и визуализировать шкалы (здоровье, ману) без подготовки дополнительных текстур, что экономит ресурсы и ускоряет разработку.

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

Живой запуск

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

Исходный код


class Example extends Phaser.Scene
{
    constructor ()
    {
        super();
    }

    preload ()
    {
        this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
        this.load.image('pixel', 'assets/sprites/16x16.png');
    }

    create ()
    {
        //  Red raster
        this.add.image(400, 150-32, 'pixel').setDisplaySize(800, 64).setTint(0x000000, 0x000000, 0xff0000, 0xff0000);
        this.add.image(400, 150+32, 'pixel').setDisplaySize(800, 64).setTint(0xff0000, 0xff0000, 0x000000, 0x000000);

        //  Green raster
        this.add.image(400, 300-32, 'pixel').setDisplaySize(800, 64).setTint(0x000000, 0x000000, 0x00ff00, 0x00ff00);
        this.add.image(400, 300+32, 'pixel').setDisplaySize(800, 64).setTint(0x00ff00, 0x00ff00, 0x000000, 0x000000);

        //  Blue raster
        this.add.image(400, 450-32, 'pixel').setDisplaySize(800, 64).setTint(0x000000, 0x000000, 0x0000ff, 0x0000ff);
        this.add.image(400, 450+32, 'pixel').setDisplaySize(800, 64).setTint(0x0000ff, 0x0000ff, 0x000000, 0x000000);
    }
}

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

const game = new Phaser.Game(config);

Как работает `setTint`?

Метод setTint применяет цветовую маску к спрайту, умножая его исходные цвета. В отличие от setFill, он работает с текстурами. Его мощь в том, что можно задать отдельный цвет для каждого из четырёх углов изображения: верхнего левого, верхнего правого, нижнего левого и нижнего правого.

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

// Синтаксис: setTint(topLeft, topRight, bottomLeft, bottomRight)
sprite.setTint(0xff0000, 0x00ff00, 0x0000ff, 0xffff00);

Анализ кода: Создание красного растра

Рассмотрим построение первой, красной полосы. Используется одна текстурка pixel размером 16x16 пикселей.

Сначала создаётся верхняя половина растра. Спрайт растягивается на 800x64 пикселей. Ключевой момент — тонирование: верхним углам задан чёрный цвет (0x000000), а нижним — красный (0xff0000). Так как цвета верхних углов одинаковы и отличаются от нижних, получается вертикальный градиент от чёрного вверху к красному внизу.

// Верхняя половина красного растра: градиент от чёрного (верх) к красному (низ)
this.add.image(400, 150-32, 'pixel')
    .setDisplaySize(800, 64)
    .setTint(0x000000, 0x000000, 0xff0000, 0xff0000);

Затем создаётся нижняя половина. Её позиция смещена вниз. Здесь градиент инвертирован: верхние углы красные, а нижние — чёрные. Вместе эти две половинки образуют полный растр с плавным переходом из чёрного в красный и обратно.

// Нижняя половина красного растра: градиент от красного (верх) к чёрному (низ)
this.add.image(400, 150+32, 'pixel')
    .setDisplaySize(800, 64)
    .setTint(0xff0000, 0xff0000, 0x000000, 0x000000);

Масштабирование и позиционирование

Поскольку исходный спрайт очень мал, для создания крупных визуальных элементов используется setDisplaySize. Этот метод растягивает или сжимает отображение спрайта, не влияя на его текстуру или систему физики (если она подключена).

// Растягиваем спрайт до ширины 800 и высоты 64 пикселя
.setDisplaySize(800, 64);

Позиция (400, 150) — это центр первой полосы. Вычитание и прибавление 32 пикселя (половины высоты спрайта после setDisplaySize) позволяет точно разместить верхнюю и нижнюю части растра вплотную друг к другу, без разрывов. Аналогичный принцип применяется для зелёной и синей полос с увеличением координаты Y.

// Позиционирование частей одной полосы
this.add.image(400, 150-32, 'pixel') // Верхняя часть
this.add.image(400, 150+32, 'pixel') // Нижняя часть

Практическое применение в играх

Эта техника полезна не только для абстрактной графики. Вот несколько практических сценариев:

* **Динамические шкалы:** Шкала здоровья может плавно менять цвет от зелёного к красному по мере уменьшения, используя всего один спрайт. * **Освещение и атмосфера:** Создание градиентных подложек для темноты, тумана или подводного эффекта. * **UI-элементы:** Стильные кнопки, панели инвентаря или фон диалоговых окон с плавными переходами цвета.

Пример кода для шкалы, которая меняет градиент в зависимости от значения (от 1.0 до 0.0):

updateHealthBar(ratio) {
    // Рассчитываем промежуточный цвет между зелёным и красным
    const green = Math.floor(0xff * ratio);
    const red = 0xff - green;
    const color = (red << 16) | (green << 8); // Формируем шестнадцатеричный цвет

    // Применяем градиент от рассчитанного цвета к чёрному
    this.healthBar.setTint(color, color, 0x000000, 0x000000);
}

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

Метод setTint в Phaser — это не просто инструмент для окрашивания спрайтов в один цвет, а целый механизм для создания аппаратно-ускоренных градиентов. Используя тонирование по углам, можно генерировать сложные цветовые переходы на лету, значительно расширяя палитру визуальных эффектов без затрат на память. Для экспериментов попробуйте: 1. Создать горизонтальный градиент, меняя цвета левых и правых углов. 2. Анимировать цвета с помощью tweens, чтобы растр "пульсировал". 3. Скомбинировать несколько растров с режимами смешивания (setBlendMode) для получения сложных текстур.