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

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

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

Живой запуск

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

Исходный код


class SceneA extends Phaser.Scene {

    constructor ()
    {
        super('SceneA');
    }

    preload ()
    {
        this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
        this.load.setPath('assets/loader-tests/');
        this.load.atlas('megaset', [ 'texture-packer-atlas-with-normals-0.png', 'texture-packer-atlas-with-normals-0_n.png' ], 'texture-packer-atlas-with-normals.json');
    }

    create ()
    {
        this.lights.enable();

        this.lights.addLight(300, 300, 300, 0xff0000, 1);
        this.lights.addLight(400, 300, 300, 0x00ff00, 1);
        this.lights.addLight(600, 500, 300, 0x0000ff, 1);

        this.input.on('pointerup', function (pointer) {

            this.scene.start('SceneB');

        }, this);

        let atlasTexture = this.textures.get('megaset');

        let frames = atlasTexture.getFrameNames();

        Phaser.Utils.Array.Shuffle(frames);

        for (let i = 0; i < frames.length; i++)
        {
            let x = Phaser.Math.Between(100, 700);
            let y = Phaser.Math.Between(100, 500);

            this.add.image(x, y, 'megaset', frames[i]).setLighting(true);
        }

        this.add.image(120, 160, 'megaset', 'contra2');
    }
}

class SceneB extends Phaser.Scene {

    constructor ()
    {
        super('SceneB');
    }

    create ()
    {
        this.lights.enable();

        let atlasTexture = this.textures.get('megaset');

        let frames = atlasTexture.getFrameNames();

        Phaser.Utils.Array.Shuffle(frames);

        for (let i = 0; i < frames.length; i++)
        {
            let x = Phaser.Math.Between(100, 700);
            let y = Phaser.Math.Between(100, 500);

            this.add.image(x, y, 'megaset', frames[i]).setLighting(true);
        }

        this.add.image(120, 160, 'megaset', 'contra2');
    }
}

var config = {
    type: Phaser.WEBGL,
    width: 800,
    height: 600,
    parent: 'phaser-example',
    scene: [ SceneA, SceneB ]
};

var game = new Phaser.Game(config);

Базовая настройка сцены и загрузка атласа

Всё начинается с объявления двух сцен, SceneA и SceneB. В методе preload первой сцены мы загружаем текстуры, включая специальный атлас с нормалями (_n.png), необходимый для корректной работы динамического освещения. Ключевой момент — установка базового URL и пути, что позволяет удобно работать с внешними ресурсами.

this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
this.load.setPath('assets/loader-tests/');
this.load.atlas('megaset', [ 'texture-packer-atlas-with-normals-0.png', 'texture-packer-atlas-with-normals-0_n.png' ], 'texture-packer-atlas-with-normals.json');

Включаем свет и добавляем источники

Чтобы активировать систему освещения в сцене, необходимо вызвать this.lights.enable(). После этого можно создавать источники света с помощью метода this.lights.addLight. В примере в SceneA добавлены три разноцветных источника: красный, зелёный и синий. Их параметры определяют положение (X, Y), радиус и цвет.

this.lights.enable();
this.lights.addLight(300, 300, 300, 0xff0000, 1);
this.lights.addLight(400, 300, 300, 0x00ff00, 1);
this.lights.addLight(600, 500, 300, 0x0000ff, 1);

Создание объектов с поддержкой освещения

После загрузки атласа мы получаем все имена его кадров через atlasTexture.getFrameNames(). Затем, перемешав их, мы случайным образом размещаем изображения по сцене. Ключевой метод для работы со светом здесь — .setLighting(true). Он указывает, что объект (спрайт) должен реагировать на источники освещения, создавая эффекты теней и бликов.

let atlasTexture = this.textures.get('megaset');
let frames = atlasTexture.getFrameNames();
Phaser.Utils.Array.Shuffle(frames);
for (let i = 0; i < frames.length; i++) {
    let x = Phaser.Math.Between(100, 700);
    let y = Phaser.Math.Between(100, 500);
    this.add.image(x, y, 'megaset', frames[i]).setLighting(true);
}

Переход между сценами по интерактивному событию

В SceneA добавлен обработчик события клика (pointerup). При срабатывании он запускает переход на SceneB с помощью this.scene.start('SceneB'). Это демонстрирует базовый паттерн управления игровым потоком. Обратите внимание, что вторая сцена (SceneB) также включает освещение (this.lights.enable()), но не создаёт отдельных источников света — сцена будет использовать глобальные настройки или оставаться тёмной, если источников нет.

this.input.on('pointerup', function (pointer) {
    this.scene.start('SceneB');
}, this);

Конфигурация игры и поддержка WebGL

Важное условие для работы динамического освещения — использование рендерера WebGL, так как система света требует соответствующих графических возможностей. В конфигурации игры явно указан type: Phaser.WEBGL. Обе сцены передаются в массиве scene, что позволяет Phaser автоматически управлять их жизненным циклом.

var config = {
    type: Phaser.WEBGL,
    width: 800,
    height: 600,
    parent: 'phaser-example',
    scene: [ SceneA, SceneB ]
};
var game = new Phaser.Game(config);

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

Вы освоили основы работы с динамическим освещением и переключением сцен в Phaser 3. Эти техники открывают путь к созданию глубоких визуальных эффектов и сложной навигации в игре. Для экспериментов попробуйте: добавить анимацию движения источников света в SceneB, изменить цвет и интенсивность света в реальном времени или реализовать плавный переход между сценами с помощью this.scene.transition. Также можно поиграть с параметрами .setLighting, чтобы увидеть, как меняется восприятие материалов объектов.