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

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

Версия 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('elephant', 'assets/sprites/elephant.png');
        this.load.image('coke', 'assets/sprites/cokecan.png');
    }

    create ()
    {
        const elephantLayer = this.add.layer();
        const cokeLayer = this.add.layer();

        for (let i = 0; i < 32; i++)
        {
            let x = Phaser.Math.Between(50, 750);
            let y = Phaser.Math.Between(100, 550);

            elephantLayer.add(this.make.sprite({ x, y, key: 'elephant' }));
        }

        for (let i = 0; i < 32; i++)
        {
            let x = Phaser.Math.Between(50, 750);
            let y = Phaser.Math.Between(100, 550);

            cokeLayer.add(this.make.sprite({ x, y, key: 'coke' }));
        }

        elephantLayer.add(cokeLayer);

        const button1 = this.add.text(10, 10, 'Hide Child Layer', { backgroundColor: '#0000aa', fixedWidth: 210, align: 'center' });
        const button2 = this.add.text(10, 48, 'Hide Parent Layer', { backgroundColor: '#0000aa', fixedWidth: 210, align: 'center' });

        button1.setPadding(0, 8, 0, 8);
        button2.setPadding(0, 8, 0, 8);

        button1.setInteractive();
        button2.setInteractive();

        button1.on('pointerdown', () => {

            cokeLayer.visible = !cokeLayer.visible;

        });

        button2.on('pointerdown', () => {

            elephantLayer.visible = !elephantLayer.visible;

        });
    }
}

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

const game = new Phaser.Game(config);

Что такое Layer и зачем он нужен

Layer — это специальный игровой объект-контейнер, который может содержать в себе другие объекты: спрайты, текст, частицы или даже другие слои. Ключевая особенность в том, что действия, примененные к слою (например, изменение свойства visible), автоматически влияют на все его дочерние элементы.

const elephantLayer = this.add.layer();
const cokeLayer = this.add.layer();

В этом примере создаются два независимых слоя. Они пока пусты, но уже готовы к добавлению объектов. Слои сами по себе не отображаются, они служат логическими группами.

Наполнение слоев объектами

Объекты добавляются в слой с помощью метода add(). В примере используется фабрика this.make.sprite() для создания спрайтов со случайными координатами. Это удобный способ быстрого прототипирования.

for (let i = 0; i < 32; i++) {
    let x = Phaser.Math.Between(50, 750);
    let y = Phaser.Math.Between(100, 550);
    elephantLayer.add(this.make.sprite({ x, y, key: 'elephant' }));
}

Важно: объект, добавленный в слой, автоматически становится его дочерним элементом в дереве отображения. Самый мощный трюк — это возможность делать слои вложенными, создавая иерархии.

elephantLayer.add(cokeLayer);

Теперь cokeLayer становится дочерним для elephantLayer. Все кансы кока-колы логически находятся «внутри» слоя со слонами.

Управление видимостью через иерархию

Свойство visible у слоя работает рекурсивно. Если скрыть родительский слой, скроются и все его дети, независимо от их собственного значения visible.

В примере создаются две текстовые кнопки, которые меняют видимость слоев.

button1.on('pointerdown', () => {
    cokeLayer.visible = !cokeLayer.visible;
});

button2.on('pointerdown', () => {
    elephantLayer.visible = !elephantLayer.visible;
});

Нажмите «Hide Child Layer» — скроются только спрайты из cokeLayer. Нажмите «Hide Parent Layer» — скроется весь elephantLayer, а вместе с ним и вложенный cokeLayer, даже если до этого он был видим. Это наглядно демонстрирует принцип иерархического управления.

Практические сценарии использования

Слои — это не просто про видимость. Их можно использовать для: * **Групповых трансформаций:** Смещение, вращение или масштабирование всего слоя. * **Логического разделения:** Отдельный слой для фона, для игровых объектов (персонажи, враги) и для интерфейса (HUD). * **Быстрого включения/выключения целых механизмов:** Например, слой со всеми объектами меню-паузы. * **Управления глубиной (depth):** Назначение глубины всему слою сразу, а не каждому объекту по отдельности.

Использование слоев делает код сцены чище и модульнее, так как логически связанные объекты собраны вместе.

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

Layer в Phaser — это фундаментальный инструмент для структурирования игрового мира. Он позволяет управлять группами объектов иерархически, что критически важно для сложных сцен. Для экспериментов попробуйте: добавить слоям свойство alpha для одновременного затухания, перемещать весь слой с помощью setX/setY или создать глубокую вложенность из 3-4 слоев, чтобы увидеть, как свойства распространяются по цепочке.