О чем этот пример
Создание атмосферных 2D-игр с динамическим освещением стало проще с нормальными картами в Phaser. Этот пример показывает, как загрузить текстуры и их нормальные карты из одного мульти-атласа, созданного в Texture Packer, и сразу использовать их для реалистичного освещения. Вы научитесь настраивать систему света и применять её к спрайтам, что мгновенно добавит глубину и настроение вашей сцене.
Версия 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.setPath('assets/loader-tests/');
this.load.multiatlas('megaset', 'texture-packer-multi-atlas-with-normals.json');
}
create ()
{
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;
});
this.add.image(0, 0, 'megaset', 'brick').setOrigin(0).setLighting(true);
const atlasTexture = this.textures.get('megaset');
const frames = atlasTexture.getFrameNames();
for (let i = 1; i < frames.length; i++)
{
const x = Phaser.Math.Between(100, 924);
const y = Phaser.Math.Between(100, 668);
this.add.image(x, y, 'megaset', frames[i]).setLighting(true);
}
}
}
const config = {
type: Phaser.WEBGL,
width: 1024,
height: 768,
parent: 'phaser-example',
scene: Example
};
const game = new Phaser.Game(config);
Загрузка мульти-атласа с нормальными картами
Ключевой момент – использование метода load.multiatlas. Он загружает JSON-файл атласа, который содержит информацию о нескольких текстурах и, что важно для нашего случая, о связанных с ними нормальных картах (normal maps). Нормальные карты используются для симуляции рельефа и взаимодействия со светом.
this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
this.load.setPath('assets/loader-tests/');
this.load.multiatlas('megaset', 'texture-packer-multi-atlas-with-normals.json');
Метод setBaseURL и setPath задают базовый путь для загрузки ресурсов. При вызове load.multiatlas первым аргументом передается ключ атласа ('megaset'), а вторым – имя JSON-файла. Phaser автоматически загрузит все изображения, указанные в этом файле, включая основные текстуры и их нормальные карты, и свяжет их в один атлас.
Настройка системы освещения
Чтобы использовать нормальные карты, необходимо активировать и настроить систему освещения Phaser. Она работает только в режиме рендеринга WEBGL.
const light = this.lights.addLight(0, 0, 200);
this.lights.enable().setAmbientColor(0x555555);
Строка this.lights.enable() активирует систему света для текущей сцены. setAmbientColor устанавливает цвет окружающего (фонового) освещения, который влияет на все объекты. this.lights.addLight создает источник динамического света. Первые два аргумента – это его начальные координаты (x, y), а третий – радиус света.
this.input.on('pointermove', pointer => {
light.x = pointer.x;
light.y = pointer.y;
});
Этот обработчик события привязывает источник света к курсору мыши, создавая эффект фонарика или движущегося источника света, что отлично демонстрирует работу нормальных карт.
Создание спрайтов с поддержкой освещения
После загрузки атласа и настройки света можно создавать спрайты. Чтобы они реагировали на свет и использовали нормальные карты, необходимо вызвать метод setLighting(true) для каждого из них.
this.add.image(0, 0, 'megaset', 'brick').setOrigin(0).setLighting(true);
Здесь создается изображение из атласа 'megaset' по конкретному имени кадра 'brick'. setOrigin(0) устанавливает точку выравнивания спрайта в его левый верхний угол. Самый важный вызов – setLighting(true). Он указывает рендереру, что для этого спрайта нужно учитывать нормальную карту и применять к нему расчеты освещения.
Чтобы добавить множество спрайтов, можно получить список всех кадров в атласе и создать их в случайных позициях.
const atlasTexture = this.textures.get('megaset');
const frames = atlasTexture.getFrameNames();
for (let i = 1; i < frames.length; i++) {
const x = Phaser.Math.Between(100, 924);
const y = Phaser.Math.Between(100, 668);
this.add.image(x, y, 'megaset', frames[i]).setLighting(true);
}
this.textures.get('megaset') получает ссылку на загруженный атлас. getFrameNames() возвращает массив имен всех кадров (текстур) внутри него. Цикл создает изображения для каждого кадра (начиная со второго, i = 1, так как первый, 'brick', уже создан) в случайных координатах, используя Phaser.Math.Between. Для каждого нового спрайта также включается освещение.
Конфигурация игры (WEBGL обязателен)
Для работы системы освещения и нормальных карт критически важно указать Phaser.WEBGL в качестве типа рендерера.
const config = {
type: Phaser.WEBGL,
width: 1024,
height: 768,
parent: 'phaser-example',
scene: Example
};
const game = new Phaser.Game(config);
Если установить тип Phaser.CANVAS, освещение и нормальные карты работать не будут. Параметры width и height задают размеры игрового холста, а parent – ID HTML-элемента, в который он будет встроен.
Что попробовать дальше
Использование мульти-атласов с нормальными картами в Phaser – это мощный прием для быстрого добавления атмосферного динамического освещения в вашу игру. Вы можете экспериментировать: добавлять несколько источников света разного цвета и радиуса, создавать статичные источники (например, костры или фонари), анимационно менять параметры света или использовать разные нормальные карты для одного спрайта для создания эффектов мокрой поверхности или повреждений.
