О чем этот пример
Работа с графикой в играх часто требует динамического изменения текстур. Phaser 3 предоставляет мощный инструмент — Canvas Texture, который позволяет создавать и модифицировать изображения прямо во время выполнения игры. Это открывает двери для реализации эффектов стирания, смешивания текстур, рисования интерфейсов или генерации процедурного контента без необходимости подгружать десятки готовых ассетов. В этой статье мы разберем, как создать текстуру на холсте, нарисовать на ней другие изображения и применить композитные операции для создания интересных визуальных эффектов.
Версия 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.image('brush', 'assets/particles/sparkle1.png');
this.load.image('grass', 'assets/textures/grass.png');
this.load.image('bg', 'assets/pics/turkey-1985086.jpg');
}
create ()
{
this.add.image(0, 0, 'bg').setOrigin(0);
const texture = this.textures.createCanvas('canvastexture', 800, 600);
const grass = this.textures.get('grass').getSourceImage();
const brush = this.textures.get('brush').getSourceImage();
texture.draw(0, 0, grass);
texture.draw(512, 0, grass);
texture.draw(0, 512, grass);
texture.draw(512, 512, grass);
// Set the global composite op:
texture.context.globalCompositeOperation = 'destination-out';
// Now anything drawn to the canvas will use this op
texture.draw(0, 0, brush);
texture.draw(150, 90, brush);
texture.draw(300, 140, brush);
// Finally, display the Canvas Texture by adding it to an Image
this.add.image(0, 0, 'canvastexture').setOrigin(0);
}
}
const config = {
type: Phaser.CANVAS,
parent: 'phaser-example',
width: 800,
height: 600,
backgroundColor: '#2d2d88',
scene: Example
};
const game = new Phaser.Game(config);
Создание Canvas Texture и загрузка ресурсов
Перед началом работы с динамическими текстурами необходимо загрузить исходные изображения. В методе preload мы используем this.load.image для загрузки трех картинок: фоновой текстуры (bg), текстуры травы (grass) и кисти (brush), которая будет выступать в роли маски или инструмента.
Ключевой момент происходит в create. Здесь мы создаем пустую текстуру на основе холста с помощью метода this.textures.createCanvas. Этот метод принимает уникальный ключ для текстуры и ее размеры.
const texture = this.textures.createCanvas('canvastexture', 800, 600);
Затем, чтобы рисовать на этом холсте другими изображениями, мы получаем их DOM-представление (объекты HTMLImageElement) с помощью метода getSourceImage().
Рисование и композитные операции
После подготовки мы можем рисовать на нашей Canvas Texture. Метод texture.draw() работает аналогично context.drawImage() в нативном Canvas API. Мы размещаем текстуру травы в четырех углах нашего холста.
texture.draw(0, 0, grass);
texture.draw(512, 0, grass);
texture.draw(0, 512, grass);
texture.draw(512, 512, grass);
Самая интересная часть — использование композитных операций. Они определяют, как новое изображение будет взаимодействовать с уже нарисованным содержимым. Мы напрямую обращаемся к контексту холста текстуры (texture.context) и меняем его свойство globalCompositeOperation. В примере используется значение 'destination-out', которое делает рисуемую область прозрачной, словно стирая ее.
texture.context.globalCompositeOperation = 'destination-out';
После установки этой операции все последующие вызовы draw будут не добавлять, а "вырезать" пиксели. Таким образом, изображения кисти создают прозрачные дыры в текстуре травы.
Отображение результата и конфигурация сцены
После всех манипуляций текстура готова. Чтобы увидеть ее в игре, мы добавляем ее на сцену как обычное изображение с помощью this.add.image, используя тот же ключ, который был задан при создании ('canvastexture').
this.add.image(0, 0, 'canvastexture').setOrigin(0);
Важно помнить, что игра в этом примере использует рендерер Phaser.CANVAS. Canvas Texture также работает и в WebGL-режиме, но под капотом Phaser будет использовать Canvas API для создания текстуры, а затем загружать ее в видеопамять как обычное изображение.
const config = {
type: Phaser.CANVAS,
parent: 'phaser-example',
width: 800,
height: 600,
backgroundColor: '#2d2d88',
scene: Example
};
Что попробовать дальше
Canvas Texture в Phaser — это мост между динамическим Canvas API и игровым рендерером. С его помощью можно создавать маски, повреждения поверхностей, интерактивные элементы, которые стираются, или генерировать уникальный визуальный контент. Для экспериментов попробуйте другие значения globalCompositeOperation (например, 'multiply', 'screen', 'overlay'), рисуйте не изображениями, а примитивами через texture.context.fillRect, или анимируйте процесс рисования, обновляя текстуру в методе update.
