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

Одной из сильных сторон Phaser является работа с графикой. Часто для сложных визуальных эффектов или оптимизации требуется подготовить текстуру в реальном времени, а затем использовать её как источник данных. В этом примере мы рассмотрим, как создать рендер-текстуру (Render Texture), наполнить её спрайтами и передать в шейдер для создания красивого туннельного эффекта. Этот подход полезен для генерации процедурных текстур, создания маск-объектов или подготовки данных для пост-обработки.

Версия Phaser: код и демо в этой статье рассчитаны на Phaser 3.90.0.

Живой запуск

Ниже встроен рабочий билд примера. Оригинальный источник: GitHub.

Исходный код


function preload ()
{
        this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
    this.load.image('apple', 'assets/sprites/apple.png');
    this.load.image('metal', 'assets/textures/alien-metal.jpg');
    this.load.glsl('bundle', 'assets/shaders/bundle.glsl.js');
}

function create()
{
    const rt = this.add.renderTexture(0, 0, 512, 512).setVisible(false);

    rt.fill(0x00066, 1, 0, 0, 512, 512);

    for (var i = 0; i < 64; i++)
    {
        rt.draw('apple', Phaser.Math.Between(50, 462), Phaser.Math.Between(50, 462));
    }

    rt.saveTexture('rt');

    const shader = this.add.shader('Tunnel', 400, 300, 800, 600, [ 'rt' ]);
}

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

const game = new Phaser.Game(config);

Загрузка ресурсов

В методе preload мы загружаем все необходимые ассеты для сцены. Обратите внимание на использование метода load.glsl для загрузки шейдеров.

function preload ()
{
    this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
    this.load.image('apple', 'assets/sprites/apple.png');
    this.load.image('metal', 'assets/textures/alien-metal.jpg');
    this.load.glsl('bundle', 'assets/shaders/bundle.glsl.js');
}

Создание и заполнение Render Texture

В методе create мы создаем невидимую рендер-текстуру размером 512x512 пикселей с помощью this.add.renderTexture. Сначала мы заливаем её темно-синим цветом, а затем в цикле рисуем 64 случайно размещенных спрайта 'apple'.

function create()
{
    const rt = this.add.renderTexture(0, 0, 512, 512).setVisible(false);
    rt.fill(0x000066, 1, 0, 0, 512, 512);
    for (var i = 0; i < 64; i++)
    {
        rt.draw('apple', Phaser.Math.Between(50, 462), Phaser.Math.Between(50, 462));
    }

Ключевые методы: - rt.fill(color, alpha, x, y, width, height) – заливка области. - rt.draw(key, x, y) – отрисовка спрайта по ключу в заданных координатах. - Phaser.Math.Between(min, max) – генерация случайного числа в диапазоне.

Сохранение текстуры и передача в шейдер

После подготовки рендер-текстуру необходимо сохранить в кэш текстур игры с уникальным ключом, чтобы другие системы могли её использовать. Это делается методом saveTexture. Затем мы создаем шейдерный объект, передавая ключ сохраненной текстуры в качестве входного параметра (uniform).

rt.saveTexture('rt');
    const shader = this.add.shader('Tunnel', 400, 300, 800, 600, [ 'rt' ]);
}

Здесь 'Tunnel' – это имя шейдера из загруженного бандла (bundle). Массив [ 'rt' ] содержит ключи текстур, которые будут переданы шейдеру.

Настройка конфигурации игры

Для работы с шейдерами и рендер-текстурами требуется контекст WebGL. Поэтому в конфигурации игры обязательно указываем type: Phaser.WEBGL.

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

const game = new Phaser.Game(config);

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

Render Texture в Phaser – это мощный инструмент для оффскринного рендеринга. Вы можете комбинировать спрайты, графику и даже другие шейдеры для создания сложных текстур в реальном времени, а затем использовать их для пост-обработки или как часть игрового процесса. Для экспериментов попробуйте: 1. Изменить алгоритм заполнения рендер-текстуры (например, рисовать спрайты в сетке или по определенной форме). 2. Использовать полученную текстуру не только в шейдере, но и как спрайт для обычного this.add.image. 3. Анимировать содержимое рендер-текстуры, перерисовывая её каждый кадр в методе update.