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

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

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

Живой запуск

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

Исходный код


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

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

    create ()
    {
        const line = new Phaser.Geom.Line(100, 200, 600, 400);
        const group = this.add.group({ key: 'ball', frameQuantity: 32 });

        Phaser.Actions.PlaceOnLine(group.getChildren(), line);
    }
}

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

const game = new Phaser.Game(config);

Подготовка сцены и создание группы

Всё начинается с базовой настройки сцены. В методе preload() мы загружаем одно изображение спрайта, которое станет прототипом для всех объектов в группе.

Затем, в create(), мы создаем геометрическую линию и группу спрайтов.

const line = new Phaser.Geom.Line(100, 200, 600, 400);
const group = this.add.group({ key: 'ball', frameQuantity: 32 });

Здесь line определяет отрезок от точки (100, 200) до точки (600, 400). Группа group создается с помощью this.add.group(), где параметр key указывает на ключ загруженного изображения, а frameQuantity — количество создаваемых спрайтов (в нашем случае, 32). Важно: на этом этапе все 32 спрайта добавлены в сцену, но их позиции по умолчанию совпадают (обычно в точке (0,0) или не определены).

Магия метода PlaceOnLine

Ключевое действие происходит в одной строке. Мы берем массив детей группы и размещаем их на нашей линии.

Phaser.Actions.PlaceOnLine(group.getChildren(), line);

Метод PlaceOnLine() принимает два основных аргумента: массив игровых объектов (полученный через group.getChildren()) и объект линии типа Phaser.Geom.Line. Алгоритм равномерно распределяет объекты вдоль всей длины отрезка. Первый объект массива будет помещен в начало линии (точка x1, y1), последний — в конец (точка x2, y2), а остальные займут промежуточные позиции с равным шагом.

Геометрия как основа

Использование Phaser.Geom.Line — это не просто способ задать две точки. Геометрические объекты в Phaser — это мощный абстрактный слой.

const line = new Phaser.Geom.Line(startX, startY, endX, endY);

Вы можете легко модифицировать линию после создания, используя методы из Phaser.Geom.Line, например, setTo() для изменения координат, что автоматически обновит расположение спрайтов, если снова применить PlaceOnLine(). Это открывает возможности для анимации самой линии и, как следствие, всего построенного на ней ряда объектов.

От статики к динамике: практические идеи

Базовый пример статичен, но его просто превратить в динамическую систему.

**1. Анимированная линия:** Изменяйте координаты линии в update(), и заново применяйте PlaceOnLine(), чтобы спрайты следовали за движущейся траекторией.

update() {
    // Двигаем конечную точку линии по кругу
    line.x2 = 400 + Math.cos(this.time.now / 500) * 200;
    line.y2 = 300 + Math.sin(this.time.now / 500) * 200;
    Phaser.Actions.PlaceOnLine(group.getChildren(), line);
}

**2. Неравномерное распределение:** Метод PlaceOnLine() распределяет объекты *равномерно*. Если нужно иное распределение (например, по кривой или с разной плотностью), вам потребуется вручную пройти по массиву объектов и рассчитать их позиции, используя методы линии, такие как getPoint(). Это показывает, что PlaceOnLine() — это удобная обёртка для частого случая, но не панацея для всех задач.

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

Phaser.Actions.PlaceOnLine — это элегантное и производительное решение для задач выравнивания и распределения объектов. Оно избавляет от рутинных математических расчетов, позволяя сосредоточиться на геймдизайне. Для экспериментов попробуйте: заменить линию на круг (Phaser.Geom.Circle) и использовать Phaser.Actions.PlaceOnCircle; менять количество спрайтов в группе в реальном времени; комбинировать PlaceOnLine с другими действиями, например RotateAround, чтобы создать эффект вращающейся цепочки.