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

При разработке игр часто возникает необходимость заставить один визуальный объект следовать за другим, например, для отображения индикатора здоровья над врагом или эффекта ауры вокруг персонажа. Phaser предоставляет для этого мощный инструмент `Phaser.Display.Align`. В этой статье мы разберем, как реализовать плавное следование спрайта за физическим телом, используя событие `postupdate`, что обеспечивает точное позиционирование в каждом кадре, независимо от скорости движения основного объекта.

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

Живой запуск

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

Исходный код


class Example extends Phaser.Scene
{
    preload ()
    {
        this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
        this.load.image('block', 'assets/sprites/block.png');
        this.load.image('flower', 'assets/sprites/flower-exo.png');
    }

    create ()
    {
        const block = this.physics.add.image(400, 100, 'block')
            .setVelocity(100, 200)
            .setBounce(1, 1)
            .setCollideWorldBounds(true);

        const flower = this.add.image(0, 0, 'flower');

        this.events.on('postupdate', () =>
        {
            Phaser.Display.Align.To.TopCenter(flower, block);
        });
    }
}

const config = {
    type: Phaser.AUTO,
    width: 800,
    height: 600,
    parent: 'phaser-example',
    physics: {
        default: 'arcade',
        arcade: { debug: true }
    },
    scene: Example
};

const game = new Phaser.Game(config);





Загрузка ресурсов и создание физического тела

В методе preload мы загружаем два изображения: block (основной объект) и flower (следящий спрайт). Базовая ссылка для загрузки устанавливается на репозиторий с примерами Phaser.

В методе create создается физическое тело — спрайт block. Он позиционируется, получает начальную скорость, коэффициент отскока и включается столкновение с границами мира. Это делает его динамическим объектом, который будет свободно двигаться и отскакивать от краев сцены.

const block = this.physics.add.image(400, 100, 'block')
    .setVelocity(100, 200)
    .setBounce(1, 1)
    .setCollideWorldBounds(true);

Спрайт flower создается как обычное изображение в точке (0, 0). Его начальная позиция не важна, так как она будет переопределена в процессе следования.

const flower = this.add.image(0, 0, 'flower');

Механизм следования через событие postupdate

Ключевой момент — использование события postupdate, которое генерируется движком Phaser после обновления логики игры, но перед рендерингом. Это идеальное место для синхронизации позиций спрайтов, так как здесь мы имеем актуальные координаты физического тела после всех расчетов физики.

Мы подписываемся на это событие с помощью this.events.on и в обработчике используем статический метод Phaser.Display.Align.To.TopCenter. Этот метод выравнивает первый спрайт (flower) относительно второго (block) по заданному правилу — в данном случае, по верхнему центру. Это означает, что flower будет размещен так, что его нижний центр окажется прямо над верхним центром block.

this.events.on('postupdate', () =>
{
    Phaser.Display.Align.To.TopCenter(flower, block);
});

Поскольку событие срабатывает каждый кадр, flower будет плавно и непрерывно следовать за движущимся block.

Настройка физики и запуск игры

Для работы примера необходимо активировать физический движок Arcade в конфигурации игры. В блоке physics мы указываем default: 'arcade' и включаем отладочный режим debug: true, который визуализирует hitbox физического тела. Это помогает при отладке, чтобы убедиться, что коллизии и позиционирование работают корректно.

const config = {
    type: Phaser.AUTO,
    width: 800,
    height: 600,
    parent: 'phaser-example',
    physics: {
        default: 'arcade',
        arcade: { debug: true }
    },
    scene: Example
};

После создания экземпляра игры new Phaser.Game(config) сцена начнет выполнение, и вы увидите, как цветок следует за прыгающим блоком.

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

Данный подход универсален и может быть использован для множества игровых элементов: * **Интерфейс:** Прикрепление полос здоровья, имен или иконок статусов к игровым объектам. * **Визуальные эффекты:** Создание ауры, свечения или частиц, которые должны точно сопровождать персонажа или врага. * **Игровая логика:** Реализация "прицела" или маркера, следующего за движущейся целью.

Метод Phaser.Display.Align.To предлагает множество других вариантов выравнивания, таких как LeftCenter, BottomRight и другие. Вы можете легко изменить правило, чтобы спрайт следовал с другой стороны объекта.

// Например, чтобы спрайт следовал снизу
Phaser.Display.Align.To.BottomCenter(follower, target);

Важно помнить, что postupdate гарантирует синхронизацию позиций после всех физических расчетов, что критично для плавности и точности в динамических сценах.

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

Использование Phaser.Display.Align в связке с событием postupdate — это надежный и эффективный способ реализовать следование одного спрайта за другим в Phaser. Этот метод обеспечивает пиксельную точность и работает независимо от скорости основного объекта. Для экспериментов попробуйте изменить правило выравнивания, добавить смещение (offset) к позиции следящего спрайта или привязать к объекту не один, а несколько спрайтов, создавая сложные композиции (например, индикатор здоровья и щита одновременно).