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

При создании игр часто возникает задача случайного расположения игровых объектов. Например, для перемешивания карт в колоде или случайного порядка появления врагов. В Phaser для этого есть удобный инструмент `Phaser.Actions.Shuffle`. Эта статья покажет, как легко и эффективно перемешивать любые объекты, входящие в группу (`Group`), и управлять их порядком отрисовки.

Версия 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('phaser', 'assets/sprites/phaser.png');
        this.load.image('atari', 'assets/sprites/atari400.png');
        this.load.image('bikku', 'assets/sprites/bikkuriman.png');
        this.load.image('block', 'assets/sprites/block.png');
        this.load.image('can', 'assets/sprites/cokecan.png');
    }

    create ()
    {
        const group = this.add.group();

        group.create(230, 200, 'atari');
        group.create(400, 200, 'phaser');
        group.create(480, 200, 'bikku');
        group.create(540, 200, 'block');
        group.create(600, 200, 'can');

        this.input.on('pointerdown', pointer =>
        {

            //  Shuffle the children
            const children = Phaser.Actions.Shuffle(group.getChildren());

            //  Assign their new depth based on their position within the Group

            for (let i = 0; i < children.length; i++)
            {
                children[i].setDepth(i);
            }

        }, this);
    }
}

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

const game = new Phaser.Game(config);

Создание группы и наполнение спрайтами

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

const group = this.add.group();
group.create(230, 200, 'atari');
group.create(400, 200, 'phaser');
group.create(480, 200, 'bikku');
group.create(540, 200, 'block');
group.create(600, 200, 'can');

Обработка клика и вызов перемешивания

Чтобы инициировать перемешивание по клику мыши, мы настраиваем слушатель события 'pointerdown'. Внутри обработчика события происходит ключевое действие — получение массива детей группы и их перемешивание.

this.input.on('pointerdown', pointer => {
    //  Получаем массив детей и перемешиваем его
    const children = Phaser.Actions.Shuffle(group.getChildren());
    // ... дальнейший код для обновления глубины
}, this);

Метод group.getChildren() возвращает массив всех объектов в группе. Функция Phaser.Actions.Shuffle() принимает этот массив, перемешивает его случайным образом и возвращает новый, перемешанный массив. Важно: исходный порядок объектов внутри самой группы не меняется, меняется только порядок в возвращаемом массиве children.

Обновление глубины отрисовки

После перемешивания порядок объектов в массиве изменился, но их depth (глубина, определяющая порядок отрисовки) осталась прежней. Чтобы визуально отразить новый порядок, мы проходим по перемешанному массиву и назначаем каждому объекту новую глубину, равную его индексу в массиве. Объект с индексом 0 будет отрисован первым (внизу), а с последним индексом — поверх остальных.

for (let i = 0; i < children.length; i++)
{
    children[i].setDepth(i);
}

Без этого шага перемешанные объекты могли бы отрисовываться в старом порядке, и визуальный эффект был бы незаметен. Метод setDepth() — стандартный способ управления z-order в Phaser 3.

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

Как и в любом проекте Phaser, нам нужна базовая конфигурация игры (config) и ее экземпляр. Конфигурация определяет тип рендерера, размеры холста, цвет фона, родительский DOM-элемент и главную сцену.

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

После создания экземпляра Phaser.Game автоматически запускается жизненный цикл сцены (preload, create, update).

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

Использование Phaser.Actions.Shuffle — это простой и эффективный способ добавить элемент случайности в расположение игровых объектов. Для экспериментов попробуйте: перемешивать объекты не по клику, а по таймеру; применять Shuffle к группам, содержащим не только спрайты, но и текст, или графические объекты; комбинировать перемешивание с другими действиями из Phaser.Actions, например, Rotate или Scale, для создания сложных анимаций.