О чем этот пример
В Phaser маскирование графики — мощный инструмент для создания сложных визуальных эффектов, таких как порталы, блики или нестандартные обрезки объектов. Классические маски (`setMask`) работают на уровне геометрии и отсекают пиксели. Однако для контейнеров (`Container`) и их содержимого часто требуется более гибкий подход — использование масок фильтров (`Filter`). В этой статье мы разберём пример, где маска накладывается не на отдельный спрайт, а на целый контейнер с несколькими изображениями, используя механизм внешних масок (`externalMask`) фильтров. Вы научитесь создавать сложные композиции, где маска влияет на всю группу объектов одновременно, что особенно полезно для UI-элементов или эффектов окружения.
Версия 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('bg1', 'assets/skies/deepblue.png');
this.load.image('bg2', 'assets/skies/wtf.png');
this.load.image('splat', 'assets/pics/splat1.png');
this.load.image('circle', 'assets/pics/mask.png');
this.load.image('atari', 'assets/sprites/atari130xe.png');
}
create ()
{
this.add.image(400, 300, 'bg1');
const container = this.add.container(400, 300);
const bg = this.add.image(0, 0, 'bg2');
const child1 = this.add.image(-120, 0, 'atari');
const child2 = this.add.image(120, 0, 'atari');
const splat = this.make.image({ x: 400, y: 300, key: 'splat', add: false });
const circle = this.make.image({ x: 300, y: 300, key: 'circle', add: false });
container.add([ bg, child1, child2 ]);
container.enableFilters();
container.filters.external.addMask(splat);
}
}
const config = {
type: Phaser.WEBGL,
parent: 'phaser-example',
width: 800,
height: 600,
scene: Example
};
const game = new Phaser.Game(config);
Подготовка ресурсов и создание контейнера
В методе preload загружаются необходимые изображения: два фона (bg1, bg2), текстура маски-кляксы (splat), изображение круга (оно не используется в коде, но загружено) и спрайт Atari (atari).
В create сначала добавляется основной фон bg1. Затем создаётся контейнер с центром в точке (400, 300) — это будут локальные координаты для всех его дочерних элементов. В контейнер помещаются: фон bg2 и два спрайта Atari, смещённые по горизонтали относительно центра контейнера.
const container = this.add.container(400, 300);
const bg = this.add.image(0, 0, 'bg2');
const child1 = this.add.image(-120, 0, 'atari');
const child2 = this.add.image(120, 0, 'atari');
container.add([ bg, child1, child2 ]);
Создание изображений для маскирования
Для работы с маской фильтра нужны объекты изображений, но они не должны автоматически добавляться на сцену. Для этого используется фабрика this.make.image с параметром add: false. Создаются два изображения: splat (клякса) и circle (круг). Хотя circle создаётся, в данном примере оно не применяется — маской служит только splat.
const splat = this.make.image({ x: 400, y: 300, key: 'splat', add: false });
const circle = this.make.image({ x: 300, y: 300, key: 'circle', add: false });
Координаты (400, 300) для splat задаются в глобальных координатах сцены, так как маска будет применяться к контейнеру, который уже расположен в этой же точке. Это обеспечивает совмещение центра маски и центра контейнера.
Включение фильтров и применение внешней маски
Ключевой шаг — активация системы фильтров для контейнера. Метод container.enableFilters() включает поддержку фильтров (в данном случае — маскирования) для этого контейнера и всех его потомков.
После этого становится доступен объект container.filters. Для наложения маски используется его свойство externalMask (вместо mask). Метод addMask принимает в качестве аргумента объект изображения (splat), созданный ранее. Маска применяется ко всему содержимому контейнера как единому целому.
container.enableFilters();
container.filters.externalMask.addMask(splat);
Важно: externalMask — это особый тип маски, который работает с системой фильтров WebGL. В отличие от стандартной маски (setMask), она не отсекает пиксели на этапе рендеринга геометрии, а применяется как пост-эффект к уже отрисованному содержимому контейнера. Это позволяет маскировать группу объектов, включая их трансформации и смешивание.
Конфигурация игры и рендеринг
Пример использует рендерер WebGL (type: Phaser.WEBGL), так как фильтры и внешние маски требуют поддержки WebGL. Конфигурация задаёт стандартный размер окна 800x600 и указывает нашу сцену Example.
const config = {
type: Phaser.WEBGL,
parent: 'phaser-example',
width: 800,
height: 600,
scene: Example
};
При запуске игры вы увидите, что контейнер с фоном bg2 и двумя спрайтами Atari отображается только в пределах формы кляксы splat. Основной фон bg1 остаётся нетронутым, так как он не входит в контейнер. Это наглядно демонстрирует изолированное действие маски на определённую группу объектов.
Что попробовать дальше
Внешние маски фильтров (externalMask) — это эффективный способ применения сложных масок к контейнерам и группам объектов в Phaser. Они работают на уровне WebGL-фильтров, что обеспечивает гибкость и производительность. Попробуйте экспериментировать: анимируйте положение маски с помощью tweens, используйте в качестве маски спрайт с прозрачностью для создания эффекта "окна" или комбинируйте несколько масок для многослойных эффектов. Также можно менять blendMode контейнера вместе с маской для создания стилизованных переходов.
