О чем этот пример
Динамические текстуры в Phaser 3 — мощный инструмент для генерации графики во время выполнения игры. В этой статье мы разберем, как создать текстуру, применив к изображению маску, и сохранить результат как новую текстуру для последующего использования. Этот подход полезен для создания уникальных визуальных эффектов, кастомных 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('mask', 'assets/pics/mask-test2.png');
this.load.image('pic', 'assets/pics/hotshot-chaos-in-tokyo.png');
}
create ()
{
const texture = this.textures.addDynamicTexture('maskedPic', 368, 290);
const pic = this.make.image({ key: 'pic', origin: { x: 0, y: 0 }, add: true });
const maskImage = this.make.image({ key: 'mask', origin: { x: 0, y: 0 }, add: false });
pic.enableFilters().filters.external.addMask(maskImage);
texture.draw(pic).render();
this.add.sprite(560, 300, 'maskedPic');
}
}
const config = {
type: Phaser.AUTO,
parent: 'phaser-example',
width: 800,
height: 600,
backgroundColor: '#2d2d6d',
scene: Example
};
const game = new Phaser.Game(config);
Загрузка ресурсов и подготовка сцены
Работа начинается с загрузки двух изображений: основного изображения (pic) и изображения, которое будет выступать в роли маски (mask). Важно, чтобы маска была изображением в градациях серого, где белые области будут пропускать изображение, а черные — скрывать его.
preload ()
{
this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
this.load.image('mask', 'assets/pics/mask-test2.png');
this.load.image('pic', 'assets/pics/hotshot-chaos-in-tokyo.png');
}
Метод setBaseURL задает базовый путь для загрузки, что упрощает указание относительных путей к файлам.
Создание динамической текстуры
Динамическая текстура — это специальный тип текстуры в Phaser, который можно рисовать программно. Мы создаем её с помощью метода this.textures.addDynamicTexture. Первым аргументом передается ключ, по которому текстура будет доступна в кэше текстур, затем — её ширина и высота.
const texture = this.textures.addDynamicTexture('maskedPic', 368, 290);
Размеры текстуры (368x290) в данном примере соответствуют размеру изображения-маски, что гарантирует корректное наложение.
Подготовка изображений и наложение маски
Далее мы создаем два игровых объекта Image из загруженных текстур. Ключевой момент — объект pic создается с флагом add: true, что автоматически добавляет его на сцену, а объект maskImage — с add: false, так как он нужен только как источник данных для маски и не должен отображаться сам по себе.
const pic = this.make.image({ key: 'pic', origin: { x: 0, y: 0 }, add: true });
const maskImage = this.make.image({ key: 'mask', origin: { x: 0, y: 0 }, add: false });
Затем для изображения pic активируется система фильтров, и к нему добавляется внешняя маска, источником которой выступает maskImage.
pic.enableFilters().filters.external.addMask(maskImage);
Метод enableFilters() включает поддержку фильтров для объекта, а filters.external.addMask() применяет маску. Теперь pic будет отображаться только в тех областях, которые определяет маска.
Рисование в текстуру и рендеринг результата
Сама по себе динамическая текстура — это чистый холст. Метод draw позволяет нарисовать на этом холсте любой отображаемый объект (в нашем случае — изображение pic с уже примененной маской). Однако, просто вызвав draw, мы лишь записываем команду. Чтобы визуализировать изменения и сделать текстуру готовой к использованию, необходимо вызвать метод render.
texture.draw(pic).render();
После выполнения этой строки в кэше текстур игры появится новая текстура с ключом 'maskedPic', содержащая исходное изображение, обрезанное по форме маски.
Использование созданной текстуры
Теперь созданную динамическую текстуру можно использовать как любую другую загруженную текстуру. В примере из неё создается спрайт и добавляется в центр сцены.
this.add.sprite(560, 300, 'maskedPic');
Это демонстрирует основное преимущество подхода: один раз создав сложный составной графический элемент (изображение + маска), мы можем использовать его как единый, готовый ассет в любом месте игры, без повторных вычислений.
Что попробовать дальше
Динамические текстуры открывают путь к procedural-графике прямо в браузере. Вы можете экспериментировать: применять несколько масок последовательно, рисовать на текстуру не только изображения, но и графики, тексты или частицы, а также модифицировать маски в реальном времени для анимации эффектов появления или преобразования объектов.
