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

Изменение визуального тона спрайта — мощный инструмент для создания атмосферных эффектов: плавного появления, исчезновения, перехода в градации серого или наложения цветового фильтра. В Phaser 3 это реализуется через систему `tint` и твины, что позволяет анимировать изменения без создания дополнительных текстур. В этой статье мы разберем, как использовать `tweens.addCounter` и `setTint` для создания плавного перехода изображения из цветного в черно-белое состояние, управляя каждым каналом цвета (RGB) через одну анимируемую переменную.

Версия 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('face', 'assets/pics/rick-and-morty-by-sawuinhaff-da64e7y.png');
    }

    create ()
    {
        const image = this.add.image(400, 300, 'face');

        this.tweens.addCounter({
            from: 255,
            to: 0,
            duration: 5000,
            onUpdate: function (tween)
            {
                const value = Math.floor(tween.getValue());

                image.setTint(Phaser.Display.Color.GetColor(value, value, value));
            }
        });
    }
}

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

const game = new Phaser.Game(config);

Зачем управлять Tint?

Метод setTint позволяет динамически окрашивать спрайт, накладывая цветовой фильтр. Это не заменяет текстуру, а модифицирует ее отображение, что очень производительно. В отличие от шейдеров, этот подход использует встроенный API Phaser и идеально подходит для простых, но эффектных переходов, таких как: * Постепенное появление/исчезновение объекта. * Симуляция эффекта вспышки или повреждения. * Плавный переход в сепию или монохром.

В нашем примере мы заставим цветное изображение плавно превратиться в черно-белое, контролируя интенсивность всех трех цветовых каналов (красного, зеленого, синего) одновременно.

Настройка сцены и загрузка

Код начинается с определения стандартной сцены Phaser 3. В методе preload мы загружаем одно изображение. Обрати внимание, что базовый URL изменяется для корректной загрузки из репозитория с примерами.

preload ()
{
    this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
    this.load.image('face', 'assets/pics/rick-and-morty-by-sawuinhaff-da64e7y.png');
}

В методе create мы создаем статичный спрайт по центру холста, используя загруженную текстуру. Объект image — это основной элемент, tint которого мы будем изменять.

create ()
{
    const image = this.add.image(400, 300, 'face');
    // ... Далее будет код с твином
}

Сердце эффекта: Tween Counter

Вместо того чтобы твинить свойства самого спрайта, мы используем this.tweens.addCounter. Этот метод создает анимацию для одного числового значения. Это значение мы будем использовать как источник для обновления цвета.

Конфигурация твина: * from: 255 — начальное значение (максимальная интенсивность для канала цвета). * to: 0 — конечное значение (отсутствие интенсивности). * duration: 5000 — длительность анимации в миллисекундах (5 секунд). * onUpdate — ключевая функция, которая вызывается при каждом обновлении твина.

this.tweens.addCounter({
    from: 255,
    to: 0,
    duration: 5000,
    onUpdate: function (tween) {
        // Логика обновления tint будет здесь
    }
});

Связывание значения твина с цветом

Функция onUpdate — это место, где происходит магия. На каждом шаге анимации мы: 1. Получаем текущее значение твина с помощью tween.getValue(). 2. Округляем его до целого числа, так как цветовые каналы требуют целочисленных значений. 3. Используем это одно значение для всех трех компонентов (R, G, B) функции Phaser.Display.Color.GetColor. Это создает оттенок серого, где R=G=B. 4. Применяем полученный цвет к спрайту через image.setTint().

Когда значение плавно уменьшается от 255 до 0, цвет спрайта изменяется от исходного (так как tint #FFFFFF его не меняет) к черному (tint #000000).

onUpdate: function (tween)
{
    const value = Math.floor(tween.getValue());
    image.setTint(Phaser.Display.Color.GetColor(value, value, value));
}

Важно: Phaser.Display.Color.GetColor возвращает целочисленное представление цвета в формате 0xRRGGBB, которое и ожидает setTint.

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

Комбинация tweens.addCounter и setTint предоставляет простой и производительный способ анимировать цветовые фильтры для объектов в Phaser 3. Этот паттерн выходит далеко за рамки перехода в черно-белое. Для экспериментов попробуйте: 1. Анимировать разные каналы (GetColor(255, value, value)) для создания перехода в "красный" тон. 2. Использовать более сложную математику в onUpdate для циклических или импульсных эффектов. 3. Привязать значение твина к другим визуальным свойствам, например, к alpha-каналу, создавая одновременное исчезновение и обесцвечивание.