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

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

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

Живой запуск

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

Исходный код


class Example extends Phaser.Scene
{
    constructor ()
    {
        super();

        this.rope;
        this.count = 0;
    }

    preload ()
    {
        this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
        this.load.image('bg', 'assets/rope/background-woof.png');
        this.load.image('dog', 'assets/rope/doggo.png');
        this.load.atlas('ui', 'assets/rope/ui-icons.png', 'assets/rope/ui-icons.json');
    }

    create ()
    {
        this.add.tileSprite(400, 300, 800, 600, 'bg');

        this.add.text(10, 10, 'Click the arrows to flip', { font: '16px Courier', fill: '#000000' }).setShadow(1, 1, '#ffffff');

        const rope = this.add.rope(400, 300, 'dog', null, 12);

        const hFlip = this.add.image(80, 600-64, 'ui', 'forward-pink').setInteractive();
        const vFlip = this.add.image(800-70, 600-80, 'ui', 'forward-pink').setAngle(-90).setInteractive();

        hFlip.on('pointerdown', () => {

            rope.toggleFlipX();

        });

        vFlip.on('pointerdown', () => {

            rope.toggleFlipY();

        });

        this.rope = rope;
    }

    update ()
    {
        this.count += 0.1;

        let points = this.rope.points;

        for (let i = 0; i < points.length; i++)
        {
            points[i].y = Math.sin(i * 0.5 + this.count) * 10;
        }

        this.rope.setDirty();
    }
}

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

let game = new Phaser.Game(config);

Инициализация сцены и загрузка ресурсов

Класс сцены наследуется от Phaser.Scene. В конструкторе инициализируются свойства для хранения ссылки на верёвку и счётчика для анимации.

В методе preload() загружаются необходимые ресурсы: фоновое изображение, текстура для верёвки (изображение собаки) и atlas для UI-кнопок. Обратите внимание на использование setBaseURL() для указания корневого пути.

preload ()
{
    this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
    this.load.image('bg', 'assets/rope/background-woof.png');
    this.load.image('dog', 'assets/rope/doggo.png');
    this.load.atlas('ui', 'assets/rope/ui-icons.png', 'assets/rope/ui-icons.json');
}

Создание Rope и интерактивных элементов

В методе create() сначала добавляется фоновый TileSprite и информационный текст.

Затем создаётся основной объект — верёвка. Ключевой вызов this.add.rope() принимает координаты (400, 300), ключ текстуры 'dog', null вместо кадра анимации (так как используется статичное изображение) и число сегментов (12). Это определяет, на сколько частей будет разбита текстура для симуляции волны.

Далее создаются две кнопки из atlas 'ui'. Для вертикальной кнопки сразу применяется поворот .setAngle(-90). Метод setInteractive() делает их кликабельными.

const rope = this.add.rope(400, 300, 'dog', null, 12);

const hFlip = this.add.image(80, 600-64, 'ui', 'forward-pink').setInteractive();
const vFlip = this.add.image(800-70, 600-80, 'ui', 'forward-pink').setAngle(-90).setInteractive();

Обработка кликов и переворот

На каждую кнопку вешается обработчик события 'pointerdown'. При клике вызываются соответствующие методы объекта rope.

toggleFlipX() инвертирует отображение верёвки по горизонтали, а toggleFlipY() — по вертикали. Эти методы меняют внутренний флаг объекта, не требуя пересоздания или дополнительной настройки текстуры. Ссылка на объект верёвки сохраняется в свойстве сцены this.rope для доступа из метода update().

hFlip.on('pointerdown', () => {
    rope.toggleFlipX();
});

vFlip.on('pointerdown', () => {
    rope.toggleFlipY();
});

this.rope = rope;

Анимация волны и обновление

Метод update() выполняется каждый кадр и создаёт волнообразное движение верёвки. Счётчик this.count увеличивается, обеспечивая плавную анимацию.

Цикл проходит по всем точкам верёвки, доступным через массив this.rope.points. Для каждой точки вычисляется новое смещение по оси Y с помощью синуса, который зависит от индекса точки и значения счётчика. Это создаёт эффект бегущей волны.

После изменения точек необходимо вручную вызвать this.rope.setDirty(). Этот метод сообщает системе рендеринга, что геометрия верёвки изменилась и её нужно перерисовать. Без этого вызова визуальные изменения не применятся.

update ()
{
    this.count += 0.1;
    let points = this.rope.points;
    for (let i = 0; i < points.length; i++)
    {
        points[i].y = Math.sin(i * 0.5 + this.count) * 10;
    }
    this.rope.setDirty();
}

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

Объект config содержит стандартные настройки для Phaser Game: тип рендерера, размеры холста, цвет фона, ID родительского DOM-элемента и класс основной сцены.

Затем создаётся экземпляр игры new Phaser.Game(config), который запускает весь цикл.

const config = {
    type: Phaser.AUTO,
    width: 800,
    height: 600,
    backgroundColor: '#000088',
    parent: 'phaser-example',
    scene: Example
};
let game = new Phaser.Game(config);

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

Объекты Rope в Phaser 3 предлагают гибкий способ работы с деформируемыми текстурами. Использование toggleFlipX/Y() позволяет мгновенно менять их ориентацию, что можно применять для зеркальных отражений воды, перевёрнутых миров или двусторонних анимаций. Для экспериментов попробуйте

  1. Привязать переворот не к клику, а к положению персонажа
  2. Анимировать не только points[i].y, но и points[i].x для сложных деформаций
  3. Комбинировать переворот с динамическим изменением текстуры верёвки