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

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

Версия 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-meadow.png');
        this.load.image('pikachu', 'assets/rope/pikachu.png');
    }

    create ()
    {
        this.add.image(400, 240, 'bg').setScale(0.8);

        //  This creates a Rope Game Object.
        //  The value 16 instructs the Rope to split itself into 16 segments.
        //  The boolean value 'false' defines the Rope segments as being vertically aligned, rather than horizontally.
        this.rope = this.add.rope(450, 300, 'pikachu', null, 16, false);

        //  You could also call this method instead:
        
        // this.rope.setVertical(16);

        //  However, it will recalculate all of the point, color and alpha data, so if you can set it in the constructor
        //  instead, it makes much more sense.
    }

    update ()
    {
        this.count += 0.1;

        let points = this.rope.points;

        for (let i = 0; i < points.length; i++)
        {
            points[i].x = Math.sin(i * 0.3 + this.count) * 16;
        }

        this.rope.setDirty();
    }
}

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

let game = new Phaser.Game(config);

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

Класс сцены Example является основным контейнером для нашего примера. В конструкторе мы инициализируем свойства для хранения ссылки на объект верёвки и счётчика для анимации.

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

preload ()
{
    this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
    this.load.image('bg', 'assets/rope/background-meadow.png');
    this.load.image('pikachu', 'assets/rope/pikachu.png');
}

Создание и настройка объекта Rope

В методе create сначала добавляется фоновое изображение. Затем создаётся ключевой объект — верёвка.

Фабричный метод this.add.rope принимает несколько аргументов: начальные координаты (x, y), ключ текстуры, фрейм (у нас null, значит, используется вся текстура), количество сегментов и ориентацию. Значение 16 разбивает верёвку на 16 частей, а false указывает, что сегменты выстроены вертикально.

this.rope = this.add.rope(450, 300, 'pikachu', null, 16, false);

Альтернативно, можно создать горизонтальную верёвку, а затем вызвать метод setVertical. Однако, как указано в комментариях, это приведёт к перерасчёту всех данных точек, поэтому задание ориентации в конструкторе предпочтительнее для производительности.

Принцип анимации точек верёвки

Динамическое поведение верёвки достигается за счёт манипуляции массивом её точек (points). Каждая точка — это объект с координатами `xиy`, определяющими позицию соответствующего сегмента.

В методе update, который вызывается на каждом кадре, мы увеличиваем счётчик count. Это создаёт непрерывно изменяющееся значение, которое используется в математической функции для анимации.

this.count += 0.1;

Затем в цикле для каждой точки вычисляется её смещение по оси X с помощью синусоидальной функции Math.sin. Аргумент синуса (i * 0.3 + this.count) обеспечивает сдвиг фазы для каждой последующей точки, создавая характерную волну.

points[i].x = Math.sin(i * 0.3 + this.count) * 16;

Множитель 16 задаёт амплитуду колебаний. Важно: мы изменяем только свойство `x` точек, так как верёвка вертикальная, и волна должна идти вбок.

Обновление отображения верёвки

После изменения координат точек в массиве необходимо явно сообщить системе рендеринга Phaser, что данные объекта изменились и его нужно перерисовать. Для этого у объекта Rope вызывается метод setDirty().

this.rope.setDirty();

Без этого вызова визуальные изменения, внесённые в массив points, не отобразятся на экране. Этот метод помечает внутренние данные верёвки как "грязные", что заставляет рендерер обновить её геометрию в следующем цикле отрисовки.

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

Код завершается стандартной для Phaser 3 конфигурацией игры. В объекте config задаются основные параметры: тип рендерера (Phaser.AUTO), размеры холста, цвет фона, идентификатор родительского HTML-элемента и класс основной сцены.

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

let game = new Phaser.Game(config);

Создание экземпляра Phaser.Game с этой конфигурацией инициализирует игровой цикл и запускает сцену Example.

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

Объект Rope в Phaser 3 — мощный инструмент для создания нежестких, программируемо анимированных элементов. Вы научились создавать вертикальную верёвку, управлять её сегментами через массив points и анимировать её, создавая волнообразное движение. Для экспериментов попробуйте: изменить амплитуду или частоту волны, анимировать координату `y` для создания "прыгающей" верёвки, привязать движение точек к курсору мыши или использовать текстуру с прозрачностью для создания эффекта дыма или магического шлейфа.