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

Работая с RenderTexture в Phaser, можно столкнуться с неожиданным поведением при отрисовке спрайтов, которым был задан оттенок (tint). Эта статья разбирает тонкости методов `fill()`, `draw()` и взаимодействия объекта спрайта с его текстурами. Понимание этих нюансов поможет избежать визуальных артефактов и даст полный контроль над динамическим рендерингом в вашей игре.

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

    create ()
    {
        const rt = this.add.renderTexture(200, 300, 256, 256);

        const sprite = this.add.image(400, 300, 'brain');

        sprite.setTint(0xff0000);

        rt.fill(0x00ff00);

        rt.draw('brain', 0, 0, 1, 0xff0000);
        rt.draw(sprite, 128, 128);
    }
}

new Phaser.Game({
  width: 800,
  height: 600,
  type: Phaser.WEBGL,
  parent: 'phaser-example',
  scene: Example
});

Разбираем код примера

В данном примере создаются два графических объекта: RenderTexture (rt) и спрайт (sprite), загруженный из изображения 'brain'. Ключевые действия происходят в методе create().

const rt = this.add.renderTexture(200, 300, 256, 256);
const sprite = this.add.image(400, 300, 'brain');

Сначала создается RenderTexture размером 256x256 пикселей с центром в точке (200, 300). Затем создается обычный спрайт в позиции (400, 300). Далее происходят три операции, влияющие на цвет.

Магия и конфликт оттенков (Tint)

Метод setTint применяет цветовой оттенок ко всему спрайту при его отрисовке на основном холсте игры. Однако это свойство также влияет на исходную текстуру спрайта.

sprite.setTint(0xff0000); // Окрашивает спрайт в красный
rt.fill(0x00ff00); // Заливает всю RenderTexture зеленым

Здесь спрайт становится красным, а RenderTexture заливается сплошным зеленым цветом. Важно понимать, что fill работает именно на целевом RenderTexture, перезаписывая все его пиксели.

Нюансы метода `draw`

Метод draw объекта RenderTexture может принимать для отрисовки как строковый ключ текстуры, так и игровой объект (например, спрайт). Поведение будет разным.

rt.draw('brain', 0, 0, 1, 0xff0000);
rt.draw(sprite, 128, 128);

Первым вызовом мы рисуем оригинальное изображение 'brain' в координаты (0,0) относительно RenderTexture, применяя к нему глобальный оттенок красного (0xff0000) и масштаб 1. Вторым вызовом мы рисуем сам спрайт sprite в координаты (128,128). Поскольку спрайту ранее был задан оттенок через setTint(0xff0000), при этой отрисовке он будет наложен на уже имеющееся содержимое RenderTexture (зеленый фон и красное изображение в углу).

Почему это важно? Практический вывод

Ключевое наблюдение: когда вы передаете в rt.draw() объект спрайта, Phaser использует его текущее визуальное состояние, включая все примененные к нему трансформации и оттенки (tint). Если же передается строковый ключ текстуры, отрисовывается ее оригинальная версия, а оттенок задается параметром метода.

Это может привести к неочевидным результатам, если вы хотите использовать спрайт как шаблон для RenderTexture, но при этом он уже визуально изменен в самой сцене. Для динамического рендеринга часто безопаснее использовать строковые ключи текстур, чтобы избежать побочных эффектов.

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

RenderTexture — мощный инструмент для динамического создания текстур, но требует внимания к источнику отрисовки. Используйте строковые ключи для предсказуемости или управляйте оттенками объекта-источника осознанно. Поэкспериментируйте: что будет, если сначала нарисовать спрайт, а потом залить RenderTexture? Или если применить clear() перед отрисовкой?