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

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

Версия 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('orb', 'assets/sprites/orb-blue.png');
    }

    create ()
    {
        //  Create 300 sprites (they all start life at 0x0)
        const group = this.add.group({ key: 'orb', frameQuantity: 300 });

        const triangle = new Phaser.Geom.Triangle.BuildEquilateral(400, 100, 380);
        // var triangle = new Phaser.Geom.Triangle.BuildRight(200, 400, 300, 200);

        //  Randomly position the sprites within the triangle
        Phaser.Actions.RandomTriangle(group.getChildren(), triangle);
    }
}

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

const game = new Phaser.Game(config);

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

Вся работа происходит в основном классе сцены, унаследованном от Phaser.Scene. На этапе preload загружается одно изображение, которое будет использовано для всех создаваемых объектов — это эффективно с точки зрения производительности.

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

В методе create мы сначала создаём группу спрайтов. Группа (Group) в Phaser — это мощный контейнер для управления множеством однотипных объектов. Используя опцию frameQuantity, мы создаём 300 спрайтов за один вызов. Изначально все они будут иметь координаты (0, 0).

const group = this.add.group({ key: 'orb', frameQuantity: 300 });

Определение целевой области: геометрия треугольника

Ключевой этап — определение области размещения. Phaser.Geom.Triangle предоставляет несколько статических методов для удобного построения треугольников. В примере используется построение равностороннего треугольника.

* BuildEquilateral(centerX, centerY, length) — создаёт равносторонний треугольник. Первые два аргумента — координаты центра описанной окружности, третий — длина стороны. * BuildRight(x, y, width, height) — создаёт прямоугольный треугольник (альтернативный вариант, закомментированный в коде).

Созданный объект triangle хранит в себе координаты трёх вершин и представляет собой геометрическую область для распределения объектов.

const triangle = new Phaser.Geom.Triangle.BuildEquilateral(400, 100, 380);
// var triangle = new Phaser.Geom.Triangle.BuildRight(200, 400, 300, 200);

Массовое распределение: Actions.RandomTriangle

Самый эффектный момент — применение действия RandomTriangle. Этот метод из пространства имён Phaser.Actions принимает два основных аргумента: 1. Массив объектов для распределения. Мы получаем его через group.getChildren(). 2. Объект треугольника (Phaser.Geom.Triangle), который задаёт границы области.

Метод перебирает все переданные спрайты и случайным образом, но равномерно, вычисляет для каждого новую позицию (`x,y`) внутри треугольника. Исходные позиции объектов (в нашем случае все 0,0) при этом игнорируются.

Phaser.Actions.RandomTriangle(group.getChildren(), triangle);

После выполнения этой строки 300 синих «орбов» окажутся аккуратно рассыпаны внутри заданного равностороннего треугольника, создавая эффект скопления или роя.

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

Код завершается стандартной для Phaser 3 конфигурацией и созданием экземпляра игры. Обратите внимание на параметр parent, который указывает ID HTML-элемента на странице, куда будет встроен canvas.

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

const game = new Phaser.Game(config);

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

Phaser.Actions.RandomTriangle — это яркий пример того, как фреймворк берёт на себя рутинную математику, позволяя разработчику сосредоточиться на творчестве. Попробуйте поэкспериментировать: измените форму треугольника на прямоугольную (BuildRight), динамически меняйте его вершины в update для создания анимированной области притяжения или комбинируйте несколько вызовов RandomTriangle с разными треугольниками и группами объектов для создания сложных составных паттернов. Это мощный инструмент для прототипирования и создания визуальных эффектов.