О чем этот пример
Создание атмосферных 2D-игр часто требует иллюзии объема и глубины. Phaser с поддержкой WebGL позволяет добиться этого эффекта с помощью динамического освещения и нормал-мап. Этот подход превращает плоские спрайты в объекты, которые визуально реагируют на свет, создавая более immersive-окружение. В статье разберем, как загрузить текстуру с нормал-мапой, настроить сцену с освещением и заставить источник света следовать за курсором мыши.
Версия Phaser: код и демо в этой статье рассчитаны на Phaser 3.90.0.
Живой запуск
Ниже встроен рабочий билд примера. Оригинальный источник: GitHub.
Исходный код
class Example extends Phaser.Scene
{
preload ()
{
this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
this.load.image({
key: 'robot',
url: 'assets/pics/equality-by-ragnarok.png',
normalMap: 'assets/normal-maps/equality-by-ragnarok_n.png'
});
}
create ()
{
this.add.image(-300, 0, 'robot').setOrigin(0).setLighting(true);
const light = this.lights.addLight(0, 0, 200);
this.lights.enable().setAmbientColor(0x555555);
this.input.on('pointermove', pointer =>
{
light.x = pointer.x;
light.y = pointer.y;
});
}
}
const config = {
type: Phaser.WEBGL,
width: 800,
height: 600,
parent: 'phaser-example',
scene: Example
};
const game = new Phaser.Game(config);
Настройка загрузки ассетов с нормал-мапой
Ключевой шаг — правильная загрузка не только основной текстуры, но и специальной карты нормалей (normal map). Нормал-мапа — это текстура, где цвет каждого пикселя кодирует информацию о направлении его поверхности (нормали). Именно эти данные используются движком освещения для расчета того, как свет должен падать на объект.
Phaser предоставляет удобный метод this.load.image() для загрузки сложных объектов изображений. Вместо строки с ключом мы передаем объект конфигурации.
this.load.image({
key: 'robot',
url: 'assets/pics/equality-by-ragnarok.png',
normalMap: 'assets/normal-maps/equality-by-ragnarok_n.png'
});
Здесь key — это уникальный идентификатор для последующего использования, url — путь к основному изображению, а normalMap — путь к карте нормалей. Обратите внимание, что для работы с освещением тип рендерера в конфигурации игры должен быть Phaser.WEBGL.
Создание сцены и включение системы освещения
После загрузки ассетов в методе create() мы настраиваем сцену. Сначала добавляем изображение на сцену с помощью this.add.image(). Важный момент — мы смещаем его по оси X в отрицательную область (-300) и устанавливаем точку привязки (origin) в `0` (левый верхний угол). Это сделано для демонстрации, чтобы часть изображения изначально была за пределами видимой области и попадала под луч света.
Затем мы активируем систему освещения. Это двухэтапный процесс:
1. Добавляем источник света с помощью `this.lights.addLight()`.
2. Включаем всю систему через `this.lights.enable()` и настраиваем общий фоновый свет.
// Добавляем изображение и включаем для него расчет освещения
this.add.image(-300, 0, 'robot').setOrigin(0).setLighting(true);
// Создаем точечный источник света с радиусом 200 пикселей
const light = this.lights.addLight(0, 0, 200);
// Включаем систему освещения и задаем цвет окружающего (фонового) света
this.lights.enable().setAmbientColor(0x555555);
Метод setLighting(true) для изображения сообщает рендереру, что при отрисовке этого спрайта нужно учитывать источники света. setAmbientColor(0x555555) устанавливает темно-серый фоновый свет, чтобы области вне радиуса основного источника не были полностью черными.
Связывание света с движением указателя мыши
Чтобы продемонстрировать эффект в действии, мы привяжем координаты источника света к положению курсора мыши. Для этого используется слушатель события pointermove, который срабатывает при каждом перемещении мыши над игровым холстом.
Внутри функции-обработчика мы просто обновляем свойства `xиyсозданного ранее объектаlight`.
this.input.on('pointermove', pointer => {
light.x = pointer.x;
light.y = pointer.y;
});
В результате, когда вы водите мышью по окну примера, источник света перемещается вместе с курсором, динамически освещая разные части изображения. Благодаря нормал-мапе создается реалистичный эффект выпуклостей и впадин на, казалось бы, плоской картинке.
Конфигурация игры: обязательный WebGL
Для работы системы освещения в Phaser 3 необходим рендерер на основе WebGL. Это указывается в главном объекте конфигурации при создании экземпляра Game.
const config = {
type: Phaser.WEBGL, // Используем WebGL-рендерер
width: 800,
height: 600,
parent: 'phaser-example',
scene: Example // Наша сцена с примером
};
const game = new Phaser.Game(config);
Если установить type: Phaser.CANVAS, система освещения и нормал-мапы работать не будут, так как Canvas-рендерер не поддерживает эти продвинутые графические функции.
Что попробовать дальше
Динамическое освещение с нормал-мапами — мощный инструмент для придания 2D-графике ощущения объема и физического присутствия в мире игры. Вы можете экспериментировать: создавать несколько источников света разного цвета и радиуса, анимировать их движение по сцене, менять параметры окружающего освещения (setAmbientColor) для создания разного времени суток или настроения. Попробуйте применить этот эффект к интерфейсу, элементам окружения или персонажам, чтобы сделать игровой мир более живым и отзывчивым.
