О чем этот пример
Создание сложных визуальных эффектов, таких как вырезание части изображения по сложной форме, часто требует подготовки масок в графических редакторах. В Phaser 3 вы можете генерировать маски динамически прямо во время выполнения игры, используя `DynamicTexture`. Это позволяет создавать интерактивные эффекты, менять форму маски в реальном времени и не загружать лишние ресурсы. В этой статье мы разберем, как использовать динамическую текстуру в качестве битмаск-маски для фильтра, чтобы накладывать одно изображение на другое по произвольной форме.
Версия 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/skies/underwater1.png');
this.load.image('bg2', 'assets/skies/toxic.png');
this.load.image('skull', 'assets/pics/skull.png');
}
create ()
{
this.add.image(400, 300, 'bg');
const banner = this.textures.addDynamicTexture('skullTexture', 800, 600)
banner.stamp('skull', null, 400, 300).render();
const image = this.add.image(400, 300, 'bg2');
image.enableFilters();
image.filters.external.addMask('skullTexture');
}
}
const config = {
type: Phaser.WEBGL,
parent: 'phaser-example',
width: 800,
height: 600,
scene: Example
};
const game = new Phaser.Game(config);
Основная идея: маска из динамической текстуры
Битмаск-маска (Bitmap Mask) в Phaser использует текстуру (изображение) для определения прозрачных и непрозрачных областей. Там, где текстура маски непрозрачна, будет видно исходное изображение. Обычно для этого используют загруженную картинку, но DynamicTexture позволяет создать такую текстуру программно.
В предоставленном примере создается динамическая текстура, на которую "штампуется" изображение черепа. Затем эта текстура применяется как внешняя маска-фильтр к другому фоновому изображению. В результате второе изображение (bg2) видно только в тех пикселях, где на текстуре-маске есть череп.
Создание и наполнение DynamicTexture
Первый шаг — создание пустой "холста" — динамической текстуры заданного размера. Для этого используется метод this.textures.addDynamicTexture(key, width, height).
Затем на эту текстуру нужно что-то нанести, чтобы она не была пустой. В примере используется метод .stamp(), который помещает изображение в центр текстуры. Важно вызвать .render(), чтобы изменения применились.
const banner = this.textures.addDynamicTexture('skullTexture', 800, 600);
banner.stamp('skull', null, 400, 300).render();
- 'skullTexture' — это уникальный ключ, по которому мы позже обратимся к текстуре для маски.
- stamp('skull', null, 400, 300) — размещает изображение с ключом 'skull' в центре текстуры (координаты 400x300). Второй параметр null означает, что используется весь кадр изображения (frame).
- .render() — финализирует операцию и делает текстуру готовой к использованию.
Применение текстуры как маски для фильтра
Чтобы применить созданную текстуру как маску, нам нужен игровой объект, поддерживающий фильтры, например Image. Сначала нужно активировать для него систему фильтров с помощью метода .enableFilters().
Затем мы обращаемся к коллекции фильтров объекта image.filters и добавляем внешнюю маску. Ключевой метод здесь — filters.external.addMask(key).
const image = this.add.image(400, 300, 'bg2');
image.enableFilters();
image.filters.external.addMask('skullTexture');
- image.enableFilters() — включает поддержку фильтров WebGL для этого конкретного объекта.
- image.filters.external.addMask('skullTexture') — указывает, что в качестве маски для фильтра объекта image должна использоваться текстура с ключом 'skullTexture'. Теперь изображение bg2 будет обрезано по форме черепа, нарисованного на этой текстуре.
Важно: исходный код примера загружает два фона. Первый (bg) добавляется обычным образом и служит нижним слоем. Второй (bg2) с маской добавляется поверх, создавая эффект "окна" в форме черепа, через которое виден первый фон.
Конфигурация проекта и сцена
Для работы с фильтрами и динамическими текстурами требуется рендерер WebGL. Это задается в конфигурации игры.
const config = {
type: Phaser.WEBGL, // Обязательно WEBGL, а не CANVAS
parent: 'phaser-example',
width: 800,
height: 600,
scene: Example
};
const game = new Phaser.Game(config);
Класс сцены Example в своем методе create выполняет всю описанную логику: создает фон, динамическую текстуру-маску и применяет ее ко второму изображению. Метод preload загружает необходимые статические ресурсы с удаленного URL.
Что попробовать дальше
Использование DynamicTexture в качестве битмаск-маски открывает путь к созданию нестатичных визуальных эффектов. Вы можете менять содержимое текстуры во время игры (добавлять новые штампы, рисовать примитивы), и маска будет обновляться в реальном времени.
**Идеи для экспериментов:**
1. Анимируйте маску: изменяйте текстуру в цикле update, рисуя на ней окружности или прямоугольники с помощью banner.fillRect или banner.stamp с другими изображениями.
2. Создайте интерактивную маску: очищайте текстуру (banner.clear()) и штампуйте изображение в позиции курсора мыши.
3. Комбинируйте несколько масок или используйте текстуру, сгенерированную из части тайловой карты (Tilemap).
