О чем этот пример

Canvas-текстуры в Phaser позволяют генерировать графические объекты динамически, прямо во время выполнения игры, без использования внешних файлов. Это мощный инструмент для создания UI-элементов, спецэффектов, прототипирования или любой графики, параметры которой могут меняться в зависимости от логики игры. В этой статье мы разберем пример создания текстуры на лету с помощью Canvas API, её добавления на сцену и последующего вращения. Вы узнаете, как это работает изнутри и почему вражение Canvas-текстур иногда выглядит иначе, чем вращение обычных спрайтов.

Версия 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('mushroom', 'assets/sprites/128x128.png');
    }

    create ()
    {
        const texture = this.textures.createCanvas('aatest', 256, 256);

        const ctx = texture.context;

        // ctx.fillStyle = '#ffffff';
        // ctx.fillRect(0, 0, 256, 256);

        ctx.strokeStyle = '#ffffff';
        ctx.lineWidth = 12;
        ctx.beginPath();
        ctx.moveTo(20, 20);
        ctx.bezierCurveTo(20, 100, 200, 100, 200, 20);
        ctx.stroke();

        texture.refresh();

        this.add.image(300, 200, 'aatest');

        this.add.image(600, 200, 'aatest').setAngle(20);

        this.add.image(300, 450, 'mushroom');
        this.add.image(600, 450, 'mushroom').setAngle(20);

    }
}

const config = {
    type: Phaser.AUTO,
    parent: 'phaser-example',
    width: 800,
    height: 600,
    scene: Example
};

const game = new Phaser.Game(config);

Создание Canvas-текстуры

В Phaser текстуры можно создавать программно, используя Canvas API. Для этого в объекте this.textures доступен метод createCanvas().

Этот метод принимает три ключевых аргумента: - Ключ текстуры (key): строка, по которой вы сможете обращаться к созданной текстуре, например, 'aatest'. - Ширина (width) и высота (height) холста в пикселях.

Метод возвращает объект текстуры, у которого есть свойство context. Это стандартный 2D-контекст Canvas (CanvasRenderingContext2D), через который вы и рисуете.

const texture = this.textures.createCanvas('aatest', 256, 256);
const ctx = texture.context;

Рисование на Canvas-контексте

После получения контекста вы можете использовать любой метод Canvas API для рисования. В примере рисуется белая кривая Безье с толщиной линии 12 пикселей.

Важный момент: после завершения рисования необходимо вызвать метод refresh() у объекта текстуры. Этот метод сообщает Phaser, что содержимое Canvas изменилось и текстуру нужно обновить в графическом конвейере. Без этого вызова ваши рисунки не появятся на экране.

ctx.strokeStyle = '#ffffff';
ctx.lineWidth = 12;
ctx.beginPath();
ctx.moveTo(20, 20);
ctx.bezierCurveTo(20, 100, 200, 100, 200, 20);
ctx.stroke();

// Критически важный шаг!
texture.refresh();

Добавление и вращение изображений

Созданную текстуру можно использовать так же, как и любую другую, загруженную через load.image(). Её ключ передается в метод this.add.image().

Метод setAngle() устанавливает угол поворота спрайта в градусах. В примере создаются два изображения на основе одной Canvas-текстуры: одно в обычном виде, другое — повернутое на 20 градусов.

this.add.image(300, 200, 'aatest');
this.add.image(600, 200, 'aatest').setAngle(20);

Сравнение с обычной текстурой

Пример наглядно демонстрирует ключевую разницу. Для сравнения на сцену добавлены два спрайта с загруженной из файла текстурой 'mushroom', один из которых также повернут на 20 градусов.

При повороте Canvas-текстуры ('aatest') Phaser по умолчанию использует билинейную фильтрацию, что может сделать края рисунка слегка размытыми. В то же время повернутая растровая текстура ('mushroom') может сохранять более четкие, пикселизированные края в зависимости от настроек рендерера и масштабирования.

this.add.image(300, 450, 'mushroom');
this.add.image(600, 450, 'mushroom').setAngle(20);

Это различие важно учитывать при создании пиксель-арт графики или когда требуется максимальная четкость.

Конфигурация и запуск игры

Как и в любом проекте Phaser, для запуска требуется создать конфигурационный объект и инстанс игры. В конфиге указывается сцена (scene), которая будет использоваться по умолчанию.

const config = {
    type: Phaser.AUTO,
    parent: 'phaser-example',
    width: 800,
    height: 600,
    scene: Example // Указываем наш класс сцены
};

const game = new Phaser.Game(config);

Что попробовать дальше

Canvas-текстуры открывают широкий простор для динамической генерации контента в Phaser. Вы можете рисовать фигуры, градиенты, текст или даже целые мини-игры прямо на текстуре. Для экспериментов попробуйте: анимировать рисунок на Canvas, изменяя его каждый кадр и вызывая refresh(); комбинировать Canvas-текстуры с масками или шейдерами; использовать их как источник для частиц (ParticleEmitter). Помните о вызове refresh() после любых изменений и учитывайте особенности фильтрации при вращении.