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

Визуальные эффекты — мощный инструмент для оживления игровых объектов. В этом примере мы используем встроенный в Phaser 3 фильтр `barrel` для создания динамической деформации спрайтов, имитирующей эффект сжатия и отскока. Такой подход позволяет добавить интерактивности и отзывчивости элементам интерфейса или игровым персонажам без необходимости создавать сложные анимации вручную. Мы разберем, как подключить фильтр, управлять его параметрами через твины и реагировать на действия игрока.

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

Живой запуск

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

Исходный код


class Block extends Phaser.GameObjects.Sprite
{
    constructor (scene, x, y)
    {
        super(scene, x, y, 'block');

        this.setScale(0.9);

        this.enableFilters();

        // Enlarge filter view.
        this.focusFiltersOverride(undefined, undefined, this.width + 64, this.height + 64);

        this.barrel = this.filters.internal.addBarrel(0.75);

        this.amount = 1;
        this.allowClick = true;

        this.setInteractive();

        this.on('pointerdown', () => this.clicked());

        this.startTween(this.amount);
    }

    startTween (amount)
    {
        this.barrel.amount = 0.75;

        this.pulseTween = this.scene.tweens.add({
            targets: this.barrel,
            amount,
            yoyo: true,
            duration: 600 - (amount * 100),
            loop: -1,
            ease: 'sine.inout'
        });
    }

    clicked ()
    {
        if (this.amount < 2 && this.allowClick)
        {
            this.pulseTween.stop();

            this.allowClick = false;

            this.scene.tweens.add({
                targets: this.barrel,
                amount: 0.3,
                duration: 100,
                yoyo: true,
                ease: 'sine.out',
                onComplete: () => this.tweenStop()
            });
        }
    }

    tweenStop ()
    {
        this.amount += 0.25;

        this.startTween(this.amount);

        this.allowClick = true;
    }

}

class Example extends Phaser.Scene
{
    preload ()
    {
        this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
        this.load.image('block', 'assets/sprites/block-slime.png');
    }

    create ()
    {
        for (let y = 0; y < 2; y++)
        {
            for (let x = 0; x < 3; x++)
            {
                this.add.existing(new Block(this, 144 + x * 256, 180 + y * 256));
            }
        }

        this.add.text(10, 16, 'Click the Blocks');
    }
}

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

const game = new Phaser.Game(config);

Подготовка и настройка фильтра

Класс Block наследуется от Phaser.GameObjects.Sprite и отвечает за интерактивный спрайт. Ключевой этап — активация и конфигурация фильтров для этого объекта.

this.enableFilters();
this.focusFiltersOverride(undefined, undefined, this.width + 64, this.height + 64);
this.barrel = this.filters.internal.addBarrel(0.75);

Метод enableFilters() включает систему фильтров для спрайта. focusFiltersOverride() расширяет область рендеринга фильтра, чтобы деформация не обрезалась краями спрайта. this.filters.internal.addBarrel(0.75) создает фильтр типа barrel с начальным значением параметра amount, равным 0.75. Этот параметр управляет силой деформации: чем больше значение, тем сильнее эффект.

Анимация эффекта с помощью твинов

Для создания плавной пульсации используется система твинов Phaser. Метод startTween запускает бесконечную анимацию, которая циклически меняет параметр amount фильтра.

this.pulseTween = this.scene.tweens.add({
    targets: this.barrel,
    amount,
    yoyo: true,
    duration: 600 - (amount * 100),
    loop: -1,
    ease: 'sine.inout'
});

Твин применяется к объекту this.barrel (нашему фильтру) и анимирует его свойство amount. Флаги yoyo: true и loop: -1 заставляют анимацию колебаться между начальным и целевым значением бесконечно. ease: 'sine.inout' задает плавное ускорение и замедление. Длительность анимации duration динамически уменьшается с ростом amount, что ускоряет пульсацию.

Обработка клика и изменение состояния

При клике на спрайт текущая анимация пульсации останавливается и запускается быстрый твин, имитирующий резкое сжатие объекта.

clicked() {
    if (this.amount < 2 && this.allowClick) {
        this.pulseTween.stop();
        this.allowClick = false;
        this.scene.tweens.add({
            targets: this.barrel,
            amount: 0.3,
            duration: 100,
            yoyo: true,
            ease: 'sine.out',
            onComplete: () => this.tweenStop()
        });
    }
}

this.pulseTween.stop() прерывает циклическую пульсацию. Новый твин резко меняет amount до 0.3 (сильное сжатие) и обратно за 100 мс. Флаг allowClick блокирует повторные клики во время анимации. После завершения твина (onComplete) вызывается tweenStop(), где увеличивается базовое значение amount и перезапускается пульсация с новой скоростью.

Создание сцены и размещение объектов

В сцене Example загружается текстура и в цикле создаются несколько экземпляров Block, которые располагаются сеткой.

create() {
    for (let y = 0; y < 2; y++) {
        for (let x = 0; x < 3; x++) {
            this.add.existing(new Block(this, 144 + x * 256, 180 + y * 256));
        }
    }
    this.add.text(10, 16, 'Click the Blocks');
}

this.add.existing() добавляет созданный объект Block в систему отображения сцены. Каждый блок получает уникальные координаты, рассчитанные на основе индексов `xиy. Текстовое поле с инструкцией создается с помощьюthis.add.text()`.

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

Фильтр barrel — это простой, но эффективный способ добавить динамическую деформацию спрайтам. Комбинируя его с системой твинов Phaser, можно создавать отзывчивые эффекты для кнопок, врагов или элементов окружения. Для экспериментов попробуйте изменить начальное значение amount, использовать другие easing-функции для твинов или применить фильтр к группе объектов одновременно. Также можно исследовать другие встроенные фильтры, такие как glow или displacement, для создания более сложных визуальных композиций.