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

Визуальные эффекты (FX) — мощный инструмент для оживления игровых объектов. Phaser 3 предоставляет встроенную систему фильтров для постобработки изображений и спрайтов прямо в рантайме, без необходимости использовать шейдеры вручную. В этой статье мы разберем пример применения фильтра "бочка" (Barrel) к изображению сердца, чтобы создать иллюзию его пульсации, сопровождаемой звуковым эффектом. Это отличная отправная точка для добавления динамики к интерфейсам, боссам или магическим заклинаниям.

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

Живой запуск

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

Исходный код


class Example extends Phaser.Scene
{
    preload ()
    {
        this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
        this.load.audio('heartbeat', 'assets/audio/heartbeat.mp3');
        this.load.image('heart', 'assets/games/card-memory-game/ui/heart.png');
    }

    create ()
    {
        // Description
        this.add.text(10, 10, 'Barrel FX', { font: '16px Courier', fill: '#00ff00' });

        const fx = this.add.image(this.sys.scale.width / 2, this.sys.scale.height / 2, 'heart');
        fx.setScale(9);

        this.image = fx;

        const barrel = fx.enableFilters().filters.external.addBarrel(1);

        this.add.tween({
            duration: 400,
            repeatDelay: 1000,
            targets: barrel,
            ease: Phaser.Math.Easing.Elastic.InOut,
            amount: 1.2,
            yoyo: true,
            repeat: -1,
            onRepeat: () => {
                this.sound.play("heartbeat");
            },
            onStart: () => {
                this.sound.play("heartbeat");
                this.add.tween({
                    duration: 400,
                    repeatDelay: 1000,
                    targets: fx,
                    ease: (value) => Math.round(value),
                    scale: 10,
                    yoyo: true,
                    repeat: -1
                })
            }
        });
    }
}

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

const game = new Phaser.Game(config);

Загрузка ресурсов

Как и в любом проекте Phaser, работа начинается с метода preload. Здесь мы загружаем два ключевых ресурса: звук сердцебиения и изображение сердца. Обратите внимание на использование this.load.setBaseURL — это удобный способ указать базовый путь для всех последующих загрузок.

this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
this.load.audio('heartbeat', 'assets/audio/heartbeat.mp3');
this.load.image('heart', 'assets/games/card-memory-game/ui/heart.png');

Создание изображения и включение фильтров

В методе create мы сначала создаем текстовую подсказку, а затем — основное изображение сердца. Ключевой момент — чтобы применить к изображению фильтр, его нужно сначала «активировать» с помощью метода enableFilters(). После этого мы получаем доступ к менеджеру фильтров filters.external и добавляем эффект «бочки» (Barrel). Изначальный параметр amount равен 1.

const fx = this.add.image(this.sys.scale.width / 2, this.sys.scale.height / 2, 'heart');
fx.setScale(9);
this.image = fx;
const barrel = fx.enableFilters().filters.external.addBarrel(1);

Анимация эффекта и звука

Вся магия происходит внутри твина (tween), который анимирует параметр amount только что созданного фильтра barrel. При значении больше 1 изображение искажается, создавая эффект раздувания или выпуклости. Твин настроен на бесконечное повторение (repeat: -1) с эффектом йо-йо (yoyo: true).

Особый интерес представляют колбэки onStart и onRepeat. В них проигрывается звук сердцебиения, а также запускается параллельный твин, который резко меняет масштаб всего изображения (scale), используя ступенчатую функцию ease, что имитирует резкий удар.

this.add.tween({
    duration: 400,
    repeatDelay: 1000,
    targets: barrel,
    ease: Phaser.Math.Easing.Elastic.InOut,
    amount: 1.2,
    yoyo: true,
    repeat: -1,
    onRepeat: () => {
        this.sound.play("heartbeat");
    },
    onStart: () => {
        this.sound.play("heartbeat");
        this.add.tween({
            duration: 400,
            repeatDelay: 1000,
            targets: fx,
            ease: (value) => Math.round(value),
            scale: 10,
            yoyo: true,
            repeat: -1
        })
    }
});

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

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

const config = {
    type: Phaser.AUTO,
    width: 800,
    height: 600,
    pixelArt: true,
    backgroundColor: '#000022',
    parent: 'phaser-example',
    scene: Example
};
const game = new Phaser.Game(config);

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

Фильтр Barrel — это простой, но эффективный способ добавить «объемность» 2D-спрайтам. Комбинируя его анимацию с твинами масштаба и звуковыми эффектами, можно создавать яркие визуальные акценты. Для экспериментов попробуйте применить этот фильтр к тексту, изменить функцию ease в твине фильтра на Sine.InOut для более плавной пульсации или анимировать другие параметры фильтра, такие как shiftX и shiftY, для создания эффекта «плывущего» изображения.