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

Создание динамического фона или эффектов параллакса — частый запрос в играх. Phaser предлагает мощный и простой инструмент для этого: `TileSprite`. В этом примере показано, как совместить статичные спрайты, текст и два тайл-спрайта, которые движутся по сложным траекториям, создавая иллюзию глубины и движения. Вы научитесь создавать и анимировать тайл-спрайты, что полезно для фонов, анимированных текстур или бесшовных паттернов.

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

Живой запуск

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

Исходный код


class Example extends Phaser.Scene
{
    iter = 0;
    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');
        this.load.image('bunny', 'assets/sprites/bunny.png');
        this.load.bitmapFont('desyrel', 'assets/fonts/bitmap/desyrel.png', 'assets/fonts/bitmap/desyrel.xml');
    }

    create ()
    {
        this.image0 = this.add.tileSprite(400, 300, 500, 500, 'image0');
        this.add.sprite(400, 300, 'bunny');
        this.image1 = this.add.tileSprite(400, 300, 150, 150, 'image1');
        this.add.bitmapText(0, 0, 'desyrel', 'Hello World');
    }

    update ()
    {
        this.image0.tilePositionX = Math.cos(this.iter) * 400;
        this.image0.tilePositionY = Math.sin(this.iter) * 400;
        this.image1.tilePositionX = Math.cos(-this.iter) * 400;
        this.image1.tilePositionY = Math.sin(-this.iter) * 400;
        this.iter += 0.01;
    }
}

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

const game = new Phaser.Game(config);

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

TileSprite — это особый тип игрового объекта в Phaser, который представляет собой повторяющееся (замостимое) изображение. В отличие от обычного спрайта, его текстуру можно смещать (tilePositionX/Y) и масштабировать (tileScaleX/Y), создавая эффекты бесконечного или движущегося фона без увеличения потребления памяти.

В данном примере создаются два тайл-спрайта: один большой (фон) и один поменьше (передний план). Их синхронное, но разнонаправленное движение создает простой, но эффективный эффект параллакса.

Загрузка ресурсов и настройка сцены

В методе preload() загружаются все необходимые изображения и шрифт. Обратите внимание на setBaseURL() — он задает базовый путь для всех последующих загрузок, что удобно для организации ресурсов.

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');
this.load.image('bunny', 'assets/sprites/bunny.png');
this.load.bitmapFont('desyrel', 'assets/fonts/bitmap/desyrel.png', 'assets/fonts/bitmap/desyrel.xml');

Метод create() создает все игровые объекты и размещает их в одном центре экрана (координаты 400, 300). Порядок добавления важен: объекты, добавленные позже, отрисовываются поверх предыдущих.

this.image0 = this.add.tileSprite(400, 300, 500, 500, 'image0');
this.add.sprite(400, 300, 'bunny');
this.image1 = this.add.tileSprite(400, 300, 150, 150, 'image1');
this.add.bitmapText(0, 0, 'desyrel', 'Hello World');

Первым создается фоновый тайл-спрайт (image0) размером 500x500. Затем обычный спрайт с кроликом (bunny). Поверх него добавляется второй, меньший тайл-спрайт (image1). Текст добавляется в левый верхний угол.

Магия анимации в методе update

Живая анимация создается в методе update(), который вызывается на каждом кадре. Здесь изменяются свойства tilePositionX и tilePositionY у обоих тайл-спрайтов. Эти свойства управляют смещением внутренней текстуры, создавая иллюзию движения самого объекта.

this.image0.tilePositionX = Math.cos(this.iter) * 400;
this.image0.tilePositionY = Math.sin(this.iter) * 400;
this.image1.tilePositionX = Math.cos(-this.iter) * 400;
this.image1.tilePositionY = Math.sin(-this.iter) * 400;
this.iter += 0.01;

Переменная iter плавно увеличивается каждые 0.01 единицы. Значения Math.cos(iter) и Math.sin(iter) дают координаты точки, движущейся по окружности. Умножение на 400 увеличивает радиус этой окружности, делая движение текстуры более быстрым и заметным. Знак минус для image1 заставляет его вращаться в противоположную сторону от image0, усиливая эффект параллакса.

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

Игра создается с базовой конфигурацией. Ключевой параметр scene указывает на наш класс Example. Используется Phaser.WEBGL рендерер для лучшей производительности.

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

const game = new Phaser.Game(config);

Цвет фона '#2d2d2d' задает темно-серый цвет за пределами игровых объектов. Параметр parent определяет ID HTML-элемента, в который будет встроен canvas игры.

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

TileSprite — это простой способ добавить сложную динамику в игру без использования тяжеловесной анимации кадр за кадром. Экспериментируйте: попробуйте менять радиус умножения (400) для изменения скорости, используйте другие тригонометрические функции для иных траекторий или анимируйте свойство tileScale для эффекта "пульсации" текстуры. Также можно привязать движение тайл-спрайта к положению камеры или игрока для создания классического параллакса в платформерах.