О чем этот пример

Создание атмосферных 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 – это мощный прием для быстрого добавления атмосферного динамического освещения в вашу игру. Вы можете экспериментировать: добавлять несколько источников света разного цвета и радиуса, создавать статичные источники (например, костры или фонари), анимационно менять параметры света или использовать разные нормальные карты для одного спрайта для создания эффектов мокрой поверхности или повреждений.