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

Фильтры камеры в Phaser — мощный инструмент для создания визуальных эффектов, не затрагивающих игровую логику. В этом примере используется фильтр Tilt-Shift, который размывает изображение по краям, оставляя резкой только узкую полосу. Этот эффект часто применяют для создания иллюзии того, что игровой мир — это маленькая миниатюра или макет. Понимание работы с `camera.filters` и настройки параметров Tilt-Shift поможет вам добавить в игру кинематографичности, выделить важные области сцены или просто создать уникальную атмосферу.

Версия 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('bg', 'assets/textures/grass.jpg');
        this.load.atlas('glade', 'assets/atlas/glade.png', 'assets/atlas/glade.json');
    }

    create ()
    {
        this.add.image(400, 300, 'bg').setScale(1.0).setScrollFactor(0, 0);

        const grass = this.add.layer();

        const trees = [ 'Spruce-1', 'Spruce-2', 'Spruce-3', 'Spruce-5', 'Spruce-6', 'Flower_2' ];

        for (let i = 0; i < 128; i++)
        {
            let x = Phaser.Math.Between(0, 800);
            let y = Phaser.Math.Between(100, 600 * 4);

            let frame = Phaser.Utils.Array.GetRandom(trees);

            let tree = this.add.image(x, y, 'glade', frame);

            tree.setDepth(y);
            tree.setOrigin(0.5, 1);

            grass.add(tree);
        }

        const camera = this.cameras.main;

        camera.filters.external.addTiltShift(0.9, 2.0, 0.4);

        this.tweens.add({
            targets: camera,
            scrollY: 1800,
            duration: 20000,
            yoyo: true,
            loop: -1
        });
    }
}

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

let game = new Phaser.Game(config);

Подготовка ресурсов и создание фона

Первым делом в методе preload() загружаются необходимые ресурсы: фоновая текстура травы и атлас спрайтов с деревьями и цветами. Атлас — это один большой файл изображения, содержащий множество маленьких спрайтов (фреймов), что позволяет оптимизировать загрузку и отрисовку.

В create() мы сразу добавляем фоновое изображение. Ключевой момент — вызов метода .setScrollFactor(0, 0). Это означает, что фон не будет прокручиваться вместе с камерой, создавая эффект параллакса нулевого уровня или статичного неба.

this.add.image(400, 300, 'bg').setScale(1.0).setScrollFactor(0, 0);

Создание слоя и процедурная расстановка деревьев

Для удобства управления группой объектов создается слой (Layer). В Phaser слои позволяют группировать игровые объекты и применять к ним общие трансформации или эффекты.

Далее в цикле создается 128 случайно размещенных деревьев. Для этого используются утилиты Phaser: - Phaser.Math.Between(min, max) генерирует случайные координаты. - Phaser.Utils.Array.GetRandom(array) выбирает случайный фрейм из подготовленного массива названий.

Каждому дереву устанавливается глубина (depth) равная его координате Y. Это стандартный прием 2.5D для создания правильного порядка отрисовки: объекты, которые находятся «ниже» на экране (с большим Y), должны перекрывать те, что «выше». Также устанавливается точка привязки (origin) в (0.5, 1), то есть в центре по X и внизу по Y. Это нужно, чтобы дерево «росло» из своей базовой точки.

const grass = this.add.layer();
const trees = [ 'Spruce-1', 'Spruce-2', 'Spruce-3', 'Spruce-5', 'Spruce-6', 'Flower_2' ];

for (let i = 0; i < 128; i++) {
    let x = Phaser.Math.Between(0, 800);
    let y = Phaser.Math.Between(100, 600 * 4);
    let frame = Phaser.Utils.Array.GetRandom(trees);
    let tree = this.add.image(x, y, 'glade', frame);
    tree.setDepth(y);
    tree.setOrigin(0.5, 1);
    grass.add(tree);
}

Применение фильтра Tilt-Shift к камере

Самый важный этап — применение фильтра. Мы получаем ссылку на основную камеру сцены и обращаемся к ее свойству filters.external. Фильтры камеры применяются ко всему, что она видит, после завершения отрисовки.

Метод addTiltShift() принимает три параметра, определяющих характер размытия: 1. **Размытие (blur)** — сила размытия (в данном случае 0.9). 2. **Градиент (gradient)** — «крутизна» перехода от резкой области к размытой (2.0). Чем выше значение, тем резче переход. 3. **Начало (start)** — точка начала эффекта (0.4 или 40% от высоты области просмотра камеры).

Фильтр создает полосу резкости, которая будет следовать за камерой.

const camera = this.cameras.main;
camera.filters.external.addTiltShift(0.9, 2.0, 0.4);

Анимация прокрутки камеры

Чтобы продемонстрировать динамику эффекта Tilt-Shift, камера приводится в движение с помощью твина. Система твинов Phaser позволяет плавно анимировать свойства объектов.

Здесь создается твин для свойства scrollY основной камеры. Он анимирует вертикальную прокрутку от начального значения до 1800 пикселей за 20 секунд. Параметры yoyo: true и loop: -1 заставляют анимацию проигрываться в прямом и обратном направлении бесконечно.

В результате мы получаем плавную «прогулку» камеры по высокому лесу, а фильтр Tilt-Shift создает иллюзию, что мы смотрим на маленькую модель.

this.tweens.add({
    targets: camera,
    scrollY: 1800,
    duration: 20000,
    yoyo: true,
    loop: -1
});

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

Фильтр Tilt-Shift — это простой, но эффективный способ drastically изменить восприятие игровой сцены, добавив ей стиля «игрушечного мира». Вы можете экспериментировать с параметрами addTiltShift(), чтобы получить более агрессивное или мягкое размытие. Попробуйте привязать начало эффекта (start) к положению игрока на экране, создавая динамическую зону резкости вокруг героя. Также поэкспериментируйте с анимацией этих параметров во время игры для создания драматичных переходов фокуса.