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

Работа с повторяющимися текстурами — обычная задача в геймдеве. В Phaser для этого есть специальный объект `TileSprite`, который эффективно рендерит крупные фоны или повторяющиеся элементы. Но что, если нужно зеркально отразить такую текстуру? В этой статье разберем, как работают флаги `flipX` и `flipY` для тайл-спрайтов, и почему их использование не требует создания дополнительных изображений в памяти. Это простой и оптимизированный способ добавить вариативности в ваши игры.

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

Живой запуск

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

Исходный код


class Example extends Phaser.Scene
{
    image1;
    image0;

    preload ()
    {
        this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
        this.load.image('image0', 'assets/pics/ra-einstein.png');
        this.load.image('image1', 'assets/sprites/mushroom2.png');
    }

    create ()
    {
        this.image0 = this.add.tileSprite(400, 300, 500.5, 500, 'image0');
        this.image1 = this.add.tileSprite(400, 300, 150, 150, 'image1');

        // image0.flipX = true;
        // image1.flipY = true;
    }
}

const config = {
    type: Phaser.CANVAS,
    width: 800,
    height: 600,
    backgroundColor: '#2d2d2d',
    parent: 'phaser-example',
    scene: Example
};

const game = new Phaser.Game(config);

Что такое TileSprite и зачем он нужен

В отличие от обычного спрайта (Sprite), который отображает одно изображение целиком, TileSprite (тайл-спрайт) предназначен для работы с повторяющимися текстурами. Вы задаете ему размер (width, height), и текстура будет заполнять эту область, при необходимости повторяясь (тайлинг). Это идеально для создания бесконечных фонов, крупных текстурных поверхностей или повторяющихся узоров без загрузки гигантских изображений.

Пример создания двух тайл-спрайтов разного размера:

this.image0 = this.add.tileSprite(400, 300, 500.5, 500, 'image0');
this.image1 = this.add.tileSprite(400, 300, 150, 150, 'image1');

Первый спрайт (image0) использует текстуру Эйнштейна размером 500.5x500 пикселей. Обратите внимание, что ширина может быть дробной. Второй спрайт (image1) — это гриб размером 150x150 пикселей. Оба отцентрированы в точке (400, 300).

Свойства flipX и flipY: зеркальное отражение на лету

Ключевая особенность тайл-спрайтов, как и многих других игровых объектов в Phaser, — наличие булевых свойств flipX и flipY. Установив их в true, вы мгновенно зеркально отражаете текстуру по горизонтали или вертикали соответственно.

Это происходит на уровне рендеринга, без создания копии исходного изображения в памяти. Phaser просто меняет порядок отрисовки текстуры внутри отведенной области. Раскомментируйте строки в исходном примере, чтобы увидеть эффект:

image0.flipX = true; // Отразить фон с Эйнштейном по горизонтали
image1.flipY = true; // Отразить спрайт гриба по вертикали

После этого image0 (текстура Эйнштейна) будет отражена зеркально слева направо, а image1 (гриб) — сверху вниз. Изменения вступают в силу немедленно в том же кадре.

Как это работает под капотом и почему это эффективно

Когда вы устанавливаете flipX или flipY, движок не манипулирует пикселями исходного изображения (текстуры). Вместо этого он меняет параметры UV-координат или матрицу трансформации, которые используются при отрисовке этого конкретного игрового объекта на холсте или WebGL-контексте.

UV-координаты — это способ «натянуть» текстуру на геометрию объекта. По умолчанию они идут от (0,0) в левом верхнем углу текстуры до (1,1) в правом нижнем. При flipX движок меняет порядок по горизонтали, например, от (1,0) до (0,1). Это крайне дешевая операция, стоимость которой сравнима с обычным перемещением или поворотом спрайта.

Такой подход дает огромное преимущество: вы можете создать одну текстуру, а затем использовать ее в нескольких тайл-спрайтах с разными вариантами отражения, не расходуя лишнюю оперативную память на хранение перевернутых копий.

Практическое применение в играх

Зеркальное отражение — это не просто визуальный эффект, а мощный инструмент для геймдизайна и оптимизации.

* **Создание симметричных уровней:** Представьте платформер с пещерой. Вы можете создать одну текстуру стены, а затем, используя flipX, сделать левую и правую часть пещеры симметричными, избегая ощущения «клонирования». * **Анимация персонажей:** Если ваш персонаж может смотреть влево и вправо, часто достаточно двух наборов анимаций (например, вид спереди и сзади). Для движения влево можно использовать спрайт для движения вправо, но с установленным flipX = true. Это сокращает объем работы художнику и размер атласа анимаций. * **Вариативность фонов:** Одна текстура травы, отраженная несколько раз, может создать более естественный и менее повторяющийся ландшафт.

Пример для симметричного фона:

// Создаем основную текстуру фона
let leftPart = this.add.tileSprite(200, 300, 400, 600, 'caveWall');
// Создаем правую часть, зеркально отразив левую
let rightPart = this.add.tileSprite(600, 300, 400, 600, 'caveWall');
rightPart.flipX = true;

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

Свойства flipX и flipY у TileSprite — это пример элегантной и производительной философии Phaser. Они позволяют добиться значительного визуального разнообразия, используя минимальные ресурсы. Для экспериментов попробуйте менять эти свойства динамически в цикле обновления (update) в зависимости от действий игрока (например, отражение спрайта при изменении направления движения) или создайте сложный узор, комбинируя несколько тайл-спрайтов с разными настройками отражения. Помните, что эти свойства работают и для обычных Sprite объектов, открывая еще больше возможностей для оптимизации арта.