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

Освещение — мощный инструмент для создания атмосферы и глубины в 2D-играх. Phaser 3 предоставляет встроенную систему освещения, которая работает в связке с нормальными картами, позволяя имитировать динамические световые эффекты. Эта статья разбирает практический пример, где точечный свет вращается вокруг анимированного спрайта-паука, создавая эффект прожектора в темноте. Вы научитесь настраивать источники света, привязывать их к геометрии и анимировать, что пригодится для создания уровней в подземельях, исследований с фонариком или просто для добавления визуального шарма вашим сценам.

Версия Phaser: код и демо в этой статье рассчитаны на Phaser 3.90.0.

Живой запуск

Ниже встроен рабочий билд примера. Оригинальный источник: GitHub.

Исходный код


class Example extends Phaser.Scene
{
    point;
    circle;
    light;
    guide;
    spider;

    preload ()
    {
        this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
        this.load.image('spider', [ 'assets/normal-maps/spider.png', 'assets/normal-maps/spider_n.png' ]);
        this.load.image('light', 'assets/normal-maps/light.png');
    }

    create ()
    {
        this.spider = this.add.sprite(400, 300, 'spider');
        this.spider.setLighting(true);

        this.light = this.lights.addLight(0, 0, 500).setIntensity(6);

        this.lights.enable().setAmbientColor(0x888888);

        //  So you can see where the light is positioned
        this.circle = new Phaser.Geom.Circle(400, 300, 200);

        this.guide = this.add.image(0, 0, 'light');
    }

    update ()
    {
        this.spider.rotation += 0.005;

        Phaser.Geom.Circle.CircumferencePoint(this.circle, this.spider.rotation - (Math.PI / 2), this.guide);

        this.light.x = this.guide.x;
        this.light.y = this.guide.y;
    }
}

const config = {
    type: Phaser.WEBGL,
    parent: 'phaser-example',
    width: 800,
    height: 600,
    scene: Example
};

const game = new Phaser.Game(config);

Настройка сцены и загрузка ассетов

Класс Example расширяет Phaser.Scene. В методе preload загружаются два ключевых изображения.

this.load.image('spider', [ 'assets/normal-maps/spider.png', 'assets/normal-maps/spider_n.png' ]);
this.load.image('light', 'assets/normal-maps/light.png');

Обратите внимание на массив для ключа 'spider'. Первый элемент — это обычная диффузная текстура, а второй (spider_n.png) — нормальная карта (normal map). Нормальная карта кодирует информацию о поверхности объекта (выступы, впадины), что необходимо для корректной работы системы освещения. Изображение 'light' — это спрайт-маркер, который будет визуально показывать позицию источника света в игре.

Создание объектов и включение освещения

В методе create происходит основная инициализация. Сначала создается спрайт паука и активируется для него расчет освещения с помощью метода setLighting(true).

this.spider = this.add.sprite(400, 300, 'spider');
this.spider.setLighting(true);

Затем создается точечный источник света. Метод this.lights.addLight(x, y, radius) добавляет свет с заданными координатами и радиусом влияния. Интенсивность света повышается до 6.

this.light = this.lights.addLight(0, 0, 500).setIntensity(6);

Чтобы система освещения начала работать, ее нужно явно включить. Также устанавливается фоновый (ambient) свет. Без него неосвещенные области были бы абсолютно черными.

this.lights.enable().setAmbientColor(0x888888);

После этого создается геометрическая окружность (Phaser.Geom.Circle) и маркер (this.guide). Окружность задает траекторию движения света, а маркер — его визуальное представление на экране.

Анимация и привязка света к траектории

В методе update происходят вычисления каждый кадр. Спрайт паука медленно вращается.

this.spider.rotation += 0.005;

Ключевой момент — вычисление точки на окружности. Статический метод Phaser.Geom.Circle.CircumferencePoint принимает окружность, угол и объект, в свойства `xиyкоторого будет записан результат. Угол берется от вращения паука, со смещением на-Math.PI/2`, чтобы свет изначально был сверху.

Phaser.Geom.Circle.CircumferencePoint(this.circle, this.spider.rotation - (Math.PI / 2), this.guide);

Полученные координаты маркера this.guide сразу же присваиваются источнику света. Таким образом, свет жестко привязан к визуальному маркеру и движется по круговой траектории вслед за вращением паука.

this.light.x = this.guide.x;
this.light.y = this.guide.y;

Конфигурация игры и запуск

Важное условие для работы освещения — использование рендерера WEBGL. В конфигурации игры 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.Game с этой конфигурацией сцена начнет свою работу, и вы увидите анимированного паука под вращающимся лучом света.

Что попробовать дальше

Вы разобрали рабочую схему динамического освещения в Phaser 3. Связка нормальных карт, источников света и геометрии открывает большие возможности. Для экспериментов попробуйте: изменить форму траектории с круга на эллипс или путь по точкам (Phaser.Curves.Path), добавить несколько независимых источников света, которые будут реагировать на движение игрока, или изменять цвет (setColor) и интенсивность света в реальном времени для создания эффекта мерцания или вспышек.