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

При создании бесконечного космического пространства или любого игрового поля, где объекты должны бесшовно появляться с противоположной стороны, можно вручную отслеживать координаты каждого спрайта. Однако в Phaser есть встроенное и эффективное решение — метод `wrap` у `physics.world`. Эта статья покажет, как с его помощью легко реализовать эффект бесконечного движения для группы объектов.

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

Живой запуск

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

Исходный код


class Example extends Phaser.Scene
{
    ufos;

    preload ()
    {
        this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
        this.load.image('space', 'assets/skies/space2.png');
        this.load.image('ufo', 'assets/sprites/ufo.png');
    }

    create ()
    {
        this.add.image(400, 300, 'space');

        this.ufos = this.physics.add.group({
            key: 'ufo',
            quantity: 48
        });

        const { x, y, width, height } = this.physics.world.bounds;

        for (const ufo of this.ufos.getChildren())
        {
            ufo.setRandomPosition(x, y, width, height);
            ufo.body.velocity.setToPolar(0.125 * Math.PI, Phaser.Math.FloatBetween(50, 100));
        }
    }

    update ()
    {
        this.physics.world.wrap(this.ufos, 24);
    }
}

const config = {
    width: 800,
    height: 600,
    parent: 'phaser-example',
    physics: {
        default: 'arcade',
        arcade: { debug: false }
    },
    scene: Example
};

const game = new Phaser.Game(config);

Понимание задачи и решения

Представьте флот НЛО, летящих по экрану. Когда объект покидает видимую область, простой подход — сбросить его координаты на противоположную сторону. Вместо ручной проверки в цикле update для каждого спрайта, Arcade Physics предоставляет метод wrap. Он автоматически проверяет границы мира и «перекидывает» объекты, обеспечивая плавное и непрерывное движение.

Это особенно полезно для симуляции звездного поля, стай астероидов или любых фоновых элементов, создающих ощущение бесконечности.

Создание и настройка физической группы

В методе create мы инициализируем группу спрайтов с физическими телами. Ключевой параметр quantity позволяет создать сразу несколько одинаковых объектов.

this.ufos = this.physics.add.group({
    key: 'ufo',
    quantity: 48
});

Далее нам нужно разбросать все созданные НЛО по всей доступной области физического мира и задать им начальную скорость. Границы мира (bounds) дают нам нужные координаты и размеры.

const { x, y, width, height } = this.physics.world.bounds;

for (const ufo of this.ufos.getChildren())
{
    ufo.setRandomPosition(x, y, width, height);
    ufo.body.velocity.setToPolar(0.125 * Math.PI, Phaser.Math.FloatBetween(50, 100));
}

setRandomPosition размещает спрайт в пределах заданного прямоугольника. setToPolar задает вектор скорости: первый аргумент — угол в радианах (0.125 * π = 45°), второй — случайная величина скорости от 50 до 100 пикселей в секунду.

Магия метода `wrap`

Вся логика «телепортации» объектов заключена в одном вызове в методе update. Этот метод игрового цикла вызывается на каждом кадре.

this.physics.world.wrap(this.ufos, 24);

Метод wrap принимает два аргумента: 1. **Объект или группу для обработки.** В нашем случае — группа this.ufos. Метод автоматически переберет всех ее детей. 2. **Отступ (padding, опционально).** Значение 24 означает, что проверка на выход за границу начнется, когда спрайт уйдет за пределы мира более чем на 24 пикселя. Это полезно для спрайтов с центром координат не в геометрическом центре или для плавного исчезновения и появления.

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

Для работы примера критически важно активировать Arcade Physics в конфигурации игры. Без этого система this.physics и метод wrap будут недоступны.

const config = {
    width: 800,
    height: 600,
    parent: 'phaser-example',
    physics: { // Включаем физику
        default: 'arcade',
        arcade: { debug: false }
    },
    scene: Example
};

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

Использование physics.world.wrap — это чистый и производительный способ создать эффект бесконечного или циклического игрового пространства. Экспериментируйте: попробуйте применить метод к отдельному спрайту, измените отступ для создания эффекта «дальнего» параллакса или комбинируйте wrap с другими силами физики, например, с setAcceleration, чтобы создать сложные траектории движения планет или комет.