О чем этот пример
В Phaser существует мощный инструмент для работы с графикой – `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('card', 'assets/pics/slug.png');
}
create ()
{
// card image is 256 x 256 in size
const area1 = this.textures.addDynamicTexture('area1', 128, 128);
const area2 = this.textures.addDynamicTexture('area2', 128, 128);
const area3 = this.textures.addDynamicTexture('area3', 128, 128);
const area4 = this.textures.addDynamicTexture('area4', 128, 128);
area1.fill(0x00ff00);
area2.fill(0x00ff00);
area3.fill(0x00ff00);
area4.fill(0x00ff00);
area1.stamp('card', null, 128, 128);
area2.stamp('card', null, 128, 128);
area3.stamp('card', null, 128, 128);
area4.stamp('card', null, 128, 128);
area1.render();
area2.render();
area3.render();
area4.render();
this.add.sprite(100, 100, 'area1').setOrigin(0);
this.add.sprite(100 + 129, 100, 'area2').setOrigin(0);
this.add.sprite(100, 100 + 129, 'area3').setOrigin(0);
this.add.sprite(100 + 129, 100 + 129, 'area4').setOrigin(0);
this.add.sprite(400, 100, 'card').setOrigin(0);
}
}
const config = {
type: Phaser.AUTO,
parent: 'phaser-example',
width: 800,
height: 600,
backgroundColor: '#2d2d6d',
scene: Example
};
const game = new Phaser.Game(config);
Что такое DynamicTexture?
DynamicTexture – это текстура, создаваемая в памяти во время выполнения игры. Она ведет себя как обычный ключ текстуры (например, загруженное изображение), но ее пиксели можно программно изменять.
Основные преимущества: - **Оптимизация**: можно собрать одну текстуру из множества мелких спрайтов (спрайтшит) для уменьшения числа draw-calls. - **Динамика**: создание текстур в реальном времени для процедурной генерации (карты, плитка, эффекты). - **Гибкость**: рисование примитивов, текста или копирование частей других текстур прямо в код.
В примере мы создадим четыре небольшие динамические текстуры и разместим на них копию загруженного изображения.
Создание и настройка динамических текстур
Первым делом, в методе preload, загружается исходное изображение card. Далее, в create, создаются четыре динамические текстуры.
Ключевой метод – this.textures.addDynamicTexture(key, width, height). Он регистрирует новую текстуру в менеджере текстур с заданным ключом и размерами.
const area1 = this.textures.addDynamicTexture('area1', 128, 128);
const area2 = this.textures.addDynamicTexture('area2', 128, 128);
const area3 = this.textures.addDynamicTexture('area3', 128, 128);
const area4 = this.textures.addDynamicTexture('area4', 128, 128);
Каждая текстура имеет размер 128x128 пикселей. После создания, методом fill мы заливаем каждую текстуру сплошным зеленым цветом (0x00ff00). Это отличный способ задать фон или очистить текстуру перед работой.
area1.fill(0x00ff00);
Метод stamp: копирование изображений
Самый интересный этап – перенос содержимого одной текстуры на другую. Для этого используется метод stamp.
area1.stamp('card', null, 128, 128);
Разберем его параметры:
1. 'card' – ключ исходной текстуры (загруженное изображение).
2. null – здесь можно передать индекс кадра или имя кадра, если используется спрайтшит. В нашем случае это не требуется.
3. 128, 128 – координаты X и Y **на динамической текстуре**, куда будет помещен **левый верхний угол** копируемого изображения.
Важный нюанс: исходное изображение card имеет размер 256x256. Метод stamp не масштабирует изображение автоматически. Он копирует пиксели из исходной текстуры в целевую, начиная с заданных координат. Если исходное изображение больше целевой текстуры, оно будет обрезано. В нашем случае, так как координаты установлены в (128, 128), а размер динамической текстуры тоже 128x128, мы скопируем только нижний правый квадрант (четверть) исходной картинки в каждый из наших зеленых квадратов.
Рендеринг и отображение на сцене
После всех операций рисования динамическую текстуру необходимо отрендерить в ее внутренний буфер. Для этого вызывается метод render().
area1.render();
area2.render();
area3.render();
area4.render();
Без этого вызова изменения (в нашем случае fill и stamp) не будут применены к финальному изображению текстуры.
Теперь текстуры готовы к использованию как обычные ресурсы. Мы создаем спрайты, указывая ключи наших динамических текстур ('area1', 'area2' и т.д.). Метод setOrigin(0) устанавливает точку привязки спрайта в его левый верхний угол, что упрощает позиционирование в сетке.
this.add.sprite(100, 100, 'area1').setOrigin(0);
this.add.sprite(100 + 129, 100, 'area2').setOrigin(0);
this.add.sprite(100, 100 + 129, 'area3').setOrigin(0);
this.add.sprite(100 + 129, 100 + 129, 'area4').setOrigin(0);
Смещение на 129 пикселей (128 размер + 1 пиксель промежуток) создает аккуратную сетку 2x2. Для сравнения, справа отображается оригинальное изображение card.
this.add.sprite(400, 100, 'card').setOrigin(0);
Что попробовать дальше
DynamicTexture – это фундаментальный инструмент для продвинутой работы с графикой в Phaser. Мы научились создавать текстуры, заливать их цветом, копировать части других изображений и отображать результат. Этот механизм лежит в основе создания динамических спрайтшитов, рисования интерфейсов, генерации ландшафтов и многих других задач.
**Идеи для экспериментов:**
1. Измените координаты в методе stamp (например, на 0, 0), чтобы копировать разные части исходного изображения.
2. Используйте fill с разными цветами для каждой текстуры перед штамповкой.
3. Создайте одну большую DynamicTexture и соберите на ней целую карту из маленьких тайлов.
4. Исследуйте другие методы, такие как draw(frame, x, y) для рисования примитивов или clear() для очистки.
