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

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

Версия 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('sonic', 'assets/sprites/sonic_havok_sanity.png');
        this.load.image('bg', 'assets/textures/gold.png');
    }

    create ()
    {
        this.add.sprite(400, 300, 'bg').setAlpha(0.2);

        const spectrum = Phaser.Display.Color.ColorSpectrum(256);

        console.log(spectrum);

        let light = this.lights.addPointLight(400, 300, 0xffffff, 16, 0.4);

        this.input.on('pointermove', pointer =>
        {

            light.x = pointer.x;
            light.y = pointer.y;

            if (pointer.isDown)
            {
                let color = Phaser.Utils.Array.GetRandom(spectrum).color;

                light = this.lights.addPointLight(pointer.x, pointer.y, color, Phaser.Math.Between(8, 32), 0.4, 0.05);
            }

        });

        this.add.sprite(680, 600, 'sonic').setOrigin(0.5, 1).setDepth(1);
    }
}

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


const game = new Phaser.Game(config);

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

Первым делом мы создаем класс сцены, наследующий от Phaser.Scene. В методе preload загружаем необходимые изображения. Обратите внимание на использование this.load.setBaseURL для удобного указания базового пути.

class Example extends Phaser.Scene
{
    preload ()
    {
        this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
        this.load.image('sonic', 'assets/sprites/sonic_havok_sanity.png');
        this.load.image('bg', 'assets/textures/gold.png');
    }

Фоновая текстура (bg) будет служить поверхностью, на которой хорошо видны эффекты света и тени. Спрайт (sonic) добавим позже для демонстрации взаимодействия света с игровыми объектами.

Создание света и цветового спектра

В методе create мы настраиваем свет и интерактивность. Сначала добавляем фоновый спрайт и делаем его полупрозрачным, чтобы световые эффекты были заметнее.

this.add.sprite(400, 300, 'bg').setAlpha(0.2);

Далее генерируем спектр из 256 цветов. Это массив объектов, содержащих цвет в числовом формате, который мы будем использовать для случайного выбора.

const spectrum = Phaser.Display.Color.ColorSpectrum(256);

Теперь создаем первый точечный источник света с помощью this.lights.addPointLight. Его параметры: позиция X/Y, начальный цвет, радиус и интенсивность.

let light = this.lights.addPointLight(400, 300, 0xffffff, 16, 0.4);

Чтобы система света работала, убедитесь, что в конфигурации игры указан type: Phaser.WEBGL, так как освещение поддерживается только в WebGL-рендерере.

Интерактивность: Свет, следующий за курсором

Мы подписываемся на событие движения указателя pointermove. В обработчике события мы просто обновляем координаты `xиy` нашего источника света, заставляя его следовать за курсором мыши.

this.input.on('pointermove', pointer =>
{
    light.x = pointer.x;
    light.y = pointer.y;

Это создает эффект фонарика или подвижного светильника, который освещает путь персонажу или подсвечивает объекты под курсором.

Создание новых источников света по клику

Расширим обработчик события движения. Если кнопка мыши нажата (pointer.isDown), мы создадим новый источник света в позиции курсора со случайными параметрами.

if (pointer.isDown)
    {
        let color = Phaser.Utils.Array.GetRandom(spectrum).color;
        light = this.lights.addPointLight(pointer.x, pointer.y, color, Phaser.Math.Between(8, 32), 0.4, 0.05);
    }

Код выполняет несколько действий: 1. Phaser.Utils.Array.GetRandom(spectrum) выбирает случайный элемент из нашего цветового спектра, из которого мы берем свойство .color. 2. Phaser.Math.Between(8, 32) генерирует случайный радиус для нового света. 3. Последний аргумент 0.05 — это коэффициент затухания (attenuation). 4. Новый свет присваивается переменной light, поэтому теперь за курсором будет следовать уже этот, только что созданный источник. Старые источники остаются на сцене, создавая шлейф из разноцветных огней.

Финализация сцены и конфигурация игры

Добавим спрайт Соника в нижнюю часть экрана, установив ему глубину (depth), чтобы он корректно отображался относительно слоя освещения.

this.add.sprite(680, 600, 'sonic').setOrigin(0.5, 1).setDepth(1);

Ключевой момент — конфигурация игры. Для работы света обязателен WebGL-рендерер.

const config = {
    type: Phaser.WEBGL, // Обязательно WEBGL
    parent: 'phaser-example',
    width: 800,
    height: 600,
    scene: Example
};

const game = new Phaser.Game(config);

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

Вы изучили основы работы с динамическим освещением в Phaser 3. Теперь у вас есть интерактивный источник света, реагирующий на действия игрока. Для дальнейших экспериментов попробуйте: 1. Добавить статические источники света для создания атмосферы (костры, фонари). 2. Использовать this.lights.enable() и .setAmbientColor() для настройки общего освещения сцены. 3. Привязать источник света к спрайту персонажа, создав эффект фонарика в темной комнате. 4. Поиграть с параметрами attenuation и intensity для создания более резких или размытых световых пятен.