О чем этот пример
В игровой графике часто требуется применять эффекты не ко всему объекту, а к его части. Например, создать иллюзию облаков, движущихся за силуэтом персонажа. В Phaser 3 для этого можно использовать спрайт как динамическую маску для фильтров. Эта техника позволяет превратить любую анимацию или изображение в «трафарет», который определяет, к каким областям тайл-спрайта или другого графического объекта применяются пиксельные фильтры (размытие, пикселизация и др.). Это мощный инструмент для создания атмосферных эффектов, параллакса с маской и нестандартных переходов.
Версия 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.atlas('walker', 'assets/animations/walker.png', 'assets/animations/walker.json');
this.load.image('sky', 'assets/skies/ms3-sky.png');
this.load.image('trees', 'assets/skies/ms3-trees.png');
}
create ()
{
this.bg = this.add.tileSprite(0, 158, 1280, 296, 'sky')
.setOrigin(0, 0);
this.trees = this.add.tileSprite(0, 400, 1280, 320, 'trees')
.setOrigin(0, 0);
const animConfig = {
key: 'walk',
frames: 'walker',
frameRate: 60,
repeat: -1
};
this.anims.create(animConfig);
const sprite = this.add.sprite(640, 120, 'walker', 'frame_0000')
.setVisible(false);
sprite.play('walk');
// Create a band of clouds.
this.clouds = this.add.tileSprite(0, 484, 1280, 296, 'sky')
.setOrigin(0, 0)
.enableFilters();
const cloudFiltersInternal = this.clouds.filters.internal;
cloudFiltersInternal.addPixelate(6);
cloudFiltersInternal.addMask(sprite);
cloudFiltersInternal.addBlur(0, 1, 1, 1);
}
update ()
{
this.bg.tilePositionX -= 2;
this.trees.tilePositionX -= 6;
this.clouds.tilePositionX += 1;
}
}
const config = {
type: Phaser.AUTO,
width: 1280,
height: 720,
backgroundColor: '#304858',
parent: 'phaser-example',
scene: Example
};
let game = new Phaser.Game(config);
Подготовка сцены и загрузка ресурсов
В методе preload загружаются необходимые ресурсы. Ключевой элемент — атлас walker с кадрами анимации персонажа. Также загружаются два фоновых изображения: небо (sky) и деревья (trees), которые будут использоваться как тайл-спрайты для создания параллакс-эффекта.
preload ()
{
this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
this.load.atlas('walker', 'assets/animations/walker.png', 'assets/animations/walker.json');
this.load.image('sky', 'assets/skies/ms3-sky.png');
this.load.image('trees', 'assets/skies/ms3-trees.png');
}
Создание анимации и маскирующего спрайта
В методе create сначала создаются фоновые слои параллакса — два тайл-спрайта. Затем конфигурируется и создается анимация walk для спрайта персонажа.
Сам спрайт-маска создается в позиции (640, 120) с начальным кадром frame_0000. Важный момент: спрайт делается невидимым (setVisible(false)), так как нам нужна только его текстура для маски, а не его отображение на сцене. После этого анимация проигрывается.
const animConfig = {
key: 'walk',
frames: 'walker',
frameRate: 60,
repeat: -1
};
this.anims.create(animConfig);
const sprite = this.add.sprite(640, 120, 'walker', 'frame_0000')
.setVisible(false);
sprite.play('walk');
Применение фильтров с маской
Создается третий тайл-спрайт clouds из текстуры неба. Для него активируется система фильтров методом enableFilters(). Далее работа идет с внутренним списком фильтров объекта: this.clouds.filters.internal.
К тайл-спрайту последовательно применяются три фильтра:
1. addPixelate(6) — делает изображение пиксельным.
2. addMask(sprite) — ключевой фильтр. В качестве маски передается наш анимированный спрайт. Теперь фильтры будут применяться только к тем частям clouds, которые попадают в непрозрачные области маски (силуэт идущего персонажа).
3. addBlur(0, 1, 1, 1) — добавляет небольшое вертикальное размытие.
this.clouds = this.add.tileSprite(0, 484, 1280, 296, 'sky')
.setOrigin(0, 0)
.enableFilters();
const cloudFiltersInternal = this.clouds.filters.internal;
cloudFiltersInternal.addPixelate(6);
cloudFiltersInternal.addMask(sprite);
cloudFiltersInternal.addBlur(0, 1, 1, 1);
В результате получается слой «облаков», который виден только сквозь силуэт идущего персонажа и имеет пиксельный, слегка размытый вид.
Анимация фона
В методе update реализуется простой параллакс-эффект за счет сдвига текстур тайл-спрайтов с разной скоростью. Фоновые слои (bg и trees) движутся влево, а слой с фильтром и маской (clouds) — вправо, создавая динамичную и живую сцену.
update ()
{
this.bg.tilePositionX -= 2;
this.trees.tilePositionX -= 6;
this.clouds.tilePositionX += 1;
}
Что попробовать дальше
Использование спрайта в качестве маски для фильтров открывает широкие возможности для постобработки графики в Phaser. Вы можете маскировать не только тайл-спрайты, но и любые другие объекты с поддержкой фильтров.
Поэкспериментируйте: используйте в качестве маски частицу (Particle), текстовый объект (Text) или тайлмап (TilemapLayer). Попробуйте комбинировать маску с другими фильтрами, например, addGlow или addBloom, чтобы создавать свечение вокруг анимированного силуэта. Можно менять свойства маски (размер, позицию, прозрачность) в реальном времени для реализации сложных переходов между сценами.
