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

TileSprite — это мощный игровой объект в Phaser 3, который позволяет использовать повторяющуюся текстуру (тайл) в качестве спрайта. В отличие от обычного спрайта, тайл можно двигать и масштабировать независимо от самого объекта, что открывает возможности для создания бесконечных фонов, анимированных текстур и сложных визуальных эффектов с минимальными затратами ресурсов. Эта статья разбирает практический пример создания TileSprite из фрейма изображения и его динамической анимации через изменение позиции и масштаба тайла. Вы научитесь управлять ключевыми свойствами `tilePosition` и `tileScale`, а также интегрировать анимацию с системой `Tweens` для плавных переходов.

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

Живой запуск

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

Исходный код


class Example extends Phaser.Scene
{
    iter = 0;
    tween;
    tilesprite;

    preload ()
    {
        this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
        this.load.image('tilesprite', 'assets/pics/alex-bisleys-horsy-512x512.png');
    }

    create ()
    {
        //  If you pass zero as the width and height it'll create a TileSprite
        //  the same size as the frame it uses
        this.tilesprite = this.add.tileSprite(400, 300, 0, 0, 'tilesprite');

        this.tween = this.tweens.addCounter({
            from: 1,
            to: 2,
            duration: 5000,
            ease: 'Sine.easeInOut',
            yoyo: true,
            repeat: -1
        });
    }

    update ()
    {
        this.tilesprite.tilePositionX = Math.cos(this.iter) * 700;
        this.tilesprite.tilePositionY = Math.sin(this.iter) * 500;

        this.tilesprite.tileScaleX = this.tween.getValue();
        this.tilesprite.tileScaleY = this.tween.getValue();

        this.iter += 0.01;
    }
}

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

const game = new Phaser.Game(config);

Инициализация и создание TileSprite

Класс Example наследуется от Phaser.Scene. В методе preload загружается изображение, которое будет использоваться как текстура для тайла.

this.load.image('tilesprite', 'assets/pics/alex-bisleys-horsy-512x512.png');

В методе create происходит ключевое действие — создание объекта TileSprite. Обратите внимание на параметры ширины и высоты, переданные как `0`.

this.tilesprite = this.add.tileSprite(400, 300, 0, 0, 'tilesprite');

Передача нуля в качестве ширины и высоты — это специальный случай. Phaser автоматически устанавливает размер TileSprite равным размеру исходного фрейма текстуры (в нашем случае 512x512 пикселей). Это удобно, когда вы хотите использовать текстуру в её оригинальном разрешении. Объект позиционируется в центре сцены по координатам (400, 300).

Настройка плавной анимации масштаба (Tween)

Для создания циклической анимации масштаба используется система твинов Phaser. Вместо того чтобы анимировать свойства самого спрайта, мы анимируем счётчик (Counter), значение которого затем применяется к тайлу.

this.tween = this.tweens.addCounter({
    from: 1,
    to: 2,
    duration: 5000,
    ease: 'Sine.easeInOut',
    yoyo: true,
    repeat: -1
});

Здесь создаётся твин-счётчик, который плавно меняет своё значение от 1 до 2 за 5 секунд, используя плавную функцию Sine.easeInOut. Параметры yoyo: true и repeat: -1 заставляют анимацию колебаться между начальным и конечным значением и повторяться бесконечно. Это значение будет использоваться для масштабирования текстуры тайла.

Динамическое обновление: движение и масштаб

Основная логика анимации находится в методе update, который вызывается на каждом кадре. Здесь управляются два ключевых свойства TileSprite: tilePosition и tileScale.

this.tilesprite.tilePositionX = Math.cos(this.iter) * 700;
this.tilesprite.tilePositionY = Math.sin(this.iter) * 500;

this.tilesprite.tileScaleX = this.tween.getValue();
this.tilesprite.tileScaleY = this.tween.getValue();

this.iter += 0.01;

1. **tilePosition**: Свойствам tilePositionX и tilePositionY присваиваются значения на основе тригонометрических функций Math.cos и Math.sin. Переменная iter увеличивается на 0.01 каждый кадр, создавая непрерывное круговое движение текстуры *внутри* границ спрайта. Умножение на 700 и 500 задаёт радиус и эллиптическую траекторию этого движения. 2. **tileScale**: Свойствам tileScaleX и tileScaleY присваивается текущее значение из твина, полученное методом getValue(). Это приводит к плавному масштабированию текстуры от 1x до 2x и обратно.

Важно понимать: изменение этих свойств влияет только на отображаемую внутри спрайта текстуру-тайл, а не на размер или положение самого игрового объекта на сцене.

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

Сцена добавляется в конфигурацию игры, которая затем создаёт экземпляр Phaser.Game.

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

const game = new Phaser.Game(config);

Это стандартная конфигурация для примера: задаётся размер холста 800x600, тёмно-серый фон и указывается, что корневым классом сцены будет наш Example. Игра автоматически запустит цикл preload, create, а затем update.

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

TileSprite — это гибкий инструмент для работы с повторяющимися и анимированными текстурами. Как показано в примере, комбинируя анимацию tilePosition для движения и tileScale для динамического масштабирования, можно создавать сложные визуальные эффекты, такие как бегущая вода, мерцающий свет или бесконечный космос. Для экспериментов попробуйте: 1. Изменить текстуру на паттерн с чёткими границами (например, кирпичную стену) и поиграть со значениями tilePosition, чтобы создать иллюзию бесконечного скроллинга. 2. Привязать изменение tilePosition к скорости игрового персонажа для создания параллакс-эффекта фона. 3. Использовать разные значения для tileScaleX и tileScaleY, чтобы добиться эффекта сжатия или растяжения текстуры.