О чем этот пример
Работа с системой освещения в Phaser 3 открывает возможности для создания атмосферных 2D-игр. Однако при добавлении динамического света часто возникает проблема: объекты, расположенные дальше от камеры, могут некорректно перекрывать ближние, нарушая восприятие глубины. Эта статья на практическом примере показывает, как синхронизировать систему глубины (Depth) с динамическим освещением (Light2D pipeline), чтобы свет корректно взаимодействовал со спрайтами в зависимости от их положения по оси Y, создавая убедительную перспективу.
Версия Phaser: код и демо в этой статье рассчитаны на Phaser 3.90.0.
Живой запуск
Ниже встроен рабочий билд примера. Оригинальный источник: GitHub.
Исходный код
class Example extends Phaser.Scene
{
constructor ()
{
super('Example');
this.character = null;
}
preload ()
{
this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
this.load.image('logo', 'assets/sprites/phaser2.png')
this.load.image('particle', 'assets/particles/yellow.png')
}
create ()
{
this.lights.enable()
this.lights.setAmbientColor(0x000000)
this.cursorKeys = this.input.keyboard.createCursorKeys()
this.light = this.lights.addLight(0, 0, 300, 0xffffff, 3)
this.character = this.add.image(500, 600, 'particle')
const image = this.add.image(500, 500, 'logo')
this.add.image(500, 300, 'particle')
image.setDepth(image.y).setPipeline('Light2D')
}
update ()
{
if (this.light && this.character)
{
const { x, y } = this.character
this.light.setPosition(x, y)
}
if (this.character)
{
if (this.cursorKeys)
{
if (this.cursorKeys.down.isDown) this.character.y += 3
if (this.cursorKeys.up.isDown) this.character.y -= 3
if (this.cursorKeys.left.isDown) this.character.x -= 3
if (this.cursorKeys.right.isDown) this.character.x += 3
}
this.character.setDepth(this.character.y)
}
}
}
const config = {
type: Phaser.AUTO,
width: 800,
height: 600,
backgroundColor: '#000000',
parent: 'phaser-example',
scene: Example
};
const game = new Phaser.Game(config);
Подготовка сцены и включение света
В методе preload загружаются необходимые ресурсы: логотип Phaser и текстура частицы. Основная настройка происходит в create.
Здесь активируется система освещения сцены и устанавливается цвет окружающего (фонового) света. Важно: установка ambient color в 0x000000 (черный) означает, что без активных источников света вся сцена будет погружена в темноту.
Также создается управляемый источник света и несколько спрайтов.
this.lights.enable()
this.lights.setAmbientColor(0x000000)
this.light = this.lights.addLight(0, 0, 300, 0xffffff, 3)
this.character = this.add.image(500, 600, 'particle')
const image = this.add.image(500, 500, 'logo')
this.add.image(500, 300, 'particle')
Ключевой принцип: связь глубины и позиции Y
Чтобы свет корректно отображался на объектах, их необходимо перевести на специальный конвейер рендеринга Light2D. Это делается методом setPipeline.
Главная "фишка" данного примера — установка глубины спрайта (setDepth) равной его координате Y. Это классический прием для 2D-игр с видом сверху или сбоку: чем больше значение Y (ниже на экране), тем объект считается "ближе" к камере и должен иметь бОльшую глубину, чтобы перекрывать объекты с меньшим Y.
image.setDepth(image.y).setPipeline('Light2D')
Обратите внимание: на другие частицы, созданные в create, конвейер Light2D не назначается. Это значит, что свет на них влиять не будет, и они останутся невидимыми на черном фоне (если не попадут в область освещения).
Динамическое обновление: свет, следующий за персонажем
В методе update реализовано две важные динамические функции.
1. Источник света постоянно следует за спрайтом character. Его позиция обновляется каждый кадр.
2. Спрайт character управляется с помощью стрелок на клавиатуре. При каждом движении его глубина (depth) пересчитывается на основе новой позиции Y.
if (this.light && this.character)
{
const { x, y } = this.character
this.light.setPosition(x, y)
}
if (this.cursorKeys.left.isDown) this.character.x -= 3
// ... остальные проверки клавиш
this.character.setDepth(this.character.y)
Таким образом, когда персонаж двигается вниз (увеличивается Y), его глубина растет, и он может визуально перекрывать объекты, находящиеся выше (с меньшим Y), а источник света, следующий за ним, корректно подсвечивает все объекты с учетом их новой иерархии отрисовки.
Настройка игры (Config)
Конфигурация игры стандартна. Ключевой момент для работы данного примера — черный цвет фона (backgroundColor: '#000000'). На темном фоне эффект от системы освещения и глубины виден наиболее четко и контрастно.
const config = {
type: Phaser.AUTO,
width: 800,
height: 600,
backgroundColor: '#000000',
parent: 'phaser-example',
scene: Example
};
Что попробовать дальше
Сочетание системы освещения Light2D и ручного управления глубиной на основе координат — мощный инструмент для создания иллюзии 3D-пространства в 2D-игре. Этот подход идеально подходит для top-down или side-view проектов, где важна перспектива.
**Идеи для экспериментов:**
1. Назначьте конвейер Light2D всем спрайтам в сцене и понаблюдайте за разницей.
2. Добавьте несколько статических или движущихся источников света с разным цветом и радиусом.
3. Измените логику расчета глубины, например, используйте setDepth(1000 - this.character.y), чтобы инвертировать порядок отрисовки.
4. Поэкспериментируйте с ненулевым ambientColor, чтобы создать эффект тусклого фонового освещения.
