О чем этот пример
Эффекты освещения способны кардинально преобразить визуал 2D-игры, добавив ей атмосферу и глубину. Phaser 3 предлагает встроенную систему света, которая работает с WebGL-рендерингом. В этой статье мы разберём практический пример, где с помощью `TileSprite` и источника света создаётся интерактивная сцена с движущейся текстурой и прожектором, управляемым курсором мыши. Вы научитесь включать освещение, настраивать ambient-свет, создавать и перемещать динамические источники, а также анимировать текстуры — всё это базовые навыки для создания современных 2D-игр с богатой графикой.
Версия Phaser: код и демо в этой статье рассчитаны на Phaser 3.90.0.
Живой запуск
Ниже встроен рабочий билд примера. Оригинальный источник: GitHub.
Исходный код
class Example extends Phaser.Scene
{
tilesprite;
preload ()
{
this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
this.load.image('brick', [ 'assets/normal-maps/brick.jpg', 'assets/normal-maps/brick_n.png' ]);
this.load.image('sonic', 'assets/sprites/sonic_havok_sanity.png');
}
create ()
{
this.tilesprite = this.add.tileSprite(400, 300, 800, 600, 'brick').setLighting(true);
this.add.sprite(680, 600, 'sonic').setOrigin(0.5, 1);
this.lights.enable();
this.lights.setAmbientColor(0x808080);
const spotlight = this.lights.addLight(400, 300, 280).setIntensity(3);
this.input.on('pointermove', pointer =>
{
spotlight.x = pointer.x;
spotlight.y = pointer.y;
});
const colors = [
0xffffff, 0xff0000, 0x00ff00, 0x00ffff, 0xff00ff, 0xffff00
];
let currentColor = 0;
this.input.on('pointerdown', pointer =>
{
currentColor++;
if (currentColor === colors.length)
{
currentColor = 0;
}
spotlight.setColor(colors[currentColor]);
});
}
update ()
{
this.tilesprite.tilePositionX += 0.3;
this.tilesprite.tilePositionY += 0.6;
}
}
const config = {
type: Phaser.WEBGL,
parent: 'phaser-example',
width: 800,
height: 600,
scene: Example
};
const game = new Phaser.Game(config);
Подготовка сцены и загрузка ассетов
Класс Example наследуется от Phaser.Scene. В методе preload() загружаются необходимые изображения. Обратите внимание на загрузку изображения 'brick': передаётся массив из двух путей. Первый путь — это обычная текстурная карта (diffuse map), а второй — карта нормалей (normal map). Карта нормалей необходима для корректного расчёта освещения, чтобы свет "обтекал" неровности текстуры. Второй загружаемый спрайт ('sonic') использует только обычную текстуру.
this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
this.load.image('brick', [ 'assets/normal-maps/brick.jpg', 'assets/normal-maps/brick_n.png' ]);
this.load.image('sonic', 'assets/sprites/sonic_havok_sanity.png');
Создание объектов и включение освещения
В методе create() создаётся игровой мир. Сначала создаётся TileSprite — спрайт с тайловой (повторяющейся) текстурой. Ключевой метод .setLighting(true) активирует для этого объекта обработку освещения. Без этого вызова свет на спрайте отображаться не будет.
this.tilesprite = this.add.tileSprite(400, 300, 800, 600, 'brick').setLighting(true);
Затем добавляется обычный спрайт Соника. Далее активируется вся система освещения сцены с помощью this.lights.enable(). Метод this.lights.setAmbientColor(0x808080) устанавливает цвет окружающего (ambient) света. Это базовый серый свет, который равномерно освещает все объекты с включённым освещением, даже без дополнительных источников.
this.lights.enable();
this.lights.setAmbientColor(0x808080);
Создание и управление динамическим источником света
Основной источник света создаётся методом this.lights.addLight(). Ему передаются начальные координаты и радиус. Метод .setIntensity(3) увеличивает интенсивность свечения в три раза от стандартной. Полученный объект spotlight сохраняется в константу для дальнейшего управления.
const spotlight = this.lights.addLight(400, 300, 280).setIntensity(3);
Для создания интерактивности на событие перемещения указателя ('pointermove') вешается обработчик. В нём координаты прожектора (spotlight.x, spotlight.y) приравниваются к координатам курсора. Таким образом, источник света следует за движением мыши.
this.input.on('pointermove', pointer => {
spotlight.x = pointer.x;
spotlight.y = pointer.y;
});
Изменение цвета света по клику
В этом блоке кода добавляется возможность менять цвет прожектора по нажатию кнопки мыши. Создаётся массив colors с шестью вариантами цветов в HEX-формате. Переключение происходит по кругу: с каждым кликом индекс currentColor увеличивается, а при достижении конца массива — сбрасывается на ноль. Цвет источника света меняется с помощью метода .setColor().
const colors = [
0xffffff, 0xff0000, 0x00ff00, 0x00ffff, 0xff00ff, 0xffff00
];
let currentColor = 0;
this.input.on('pointerdown', pointer => {
currentColor++;
if (currentColor === colors.length) {
currentColor = 0;
}
spotlight.setColor(colors[currentColor]);
});
Анимация фоновой текстуры
Чтобы сцена не была статичной, в методе update(), который вызывается каждый кадр, происходит смещение внутренней позиции тайлов текстуры TileSprite. Изменяя свойства .tilePositionX и .tilePositionY, мы создаём иллюзию плавного движения фонового кирпича. Это простой и эффективный способ анимировать большие фоны без использования спрайт-листов или тяжёлой логики.
update ()
{
this.tilesprite.tilePositionX += 0.3;
this.tilesprite.tilePositionY += 0.6;
}
Конфигурация и запуск игры
Важнейший момент: для работы системы освещения в конфигурации игры type должен быть установлен в Phaser.WEBGL. CANVAS-рендерер не поддерживает эту функциональность. В конфиге указывается родительский элемент, размеры холста и класс основной сцены.
const config = {
type: Phaser.WEBGL,
parent: 'phaser-example',
width: 800,
height: 600,
scene: Example
};
const game = new Phaser.Game(config);
Что попробовать дальше
Вы изучили основы работы с системой динамического освещения в Phaser 3. Вы можете создавать статические и движущиеся источники света, менять их параметры в реальном времени и применять освещение к тайловым спрайтам и другим объектам. Для экспериментов попробуйте: добавить несколько независимых источников света, привязать свет к движущемуся игровому персонажу вместо курсора, изменить параметры ambient-освещения для создания разного времени суток или использовать другие типы текстур с картами нормалей для более сложных визуальных эффектов.
