О чем этот пример
Современные игры живут атмосферой, и свет — один из её главных создателей. В этом примере мы разберём, как в 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, чтобы увидеть, как меняется восприятие материалов объектов.
