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

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

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

Живой запуск

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

Исходный код


class Example extends Phaser.Scene
{
    constructor ()
    {
        super();
    }

    create ()
    {
        this.add.text(10, 10, 'Wheel: Hue\nA + D: Radius\nW + S: Attenuation\nClick to set Light').setDepth(1);

        let colorIndex = 0;
        const spectrum = Phaser.Display.Color.ColorSpectrum(128);

        let radius = 128;
        let intensity = 1;
        let attenuation = 0.1;

        let light = this.add.pointlight(400, 300, 0, radius, intensity);

        let color = spectrum[colorIndex];

        light.color.setTo(color.r, color.g, color.b);

        colorIndex++;

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

            light = this.add.pointlight(pointer.x, pointer.y, 0, radius, intensity);

            light.attenuation = attenuation;
            light.color.setTo(color.r, color.g, color.b);

        });

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

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

        });

        this.input.on('wheel', (pointer, over, deltaX, deltaY, deltaZ) => {

            if (deltaY < 0)
            {
                colorIndex--;
            }
            else if (deltaY > 0)
            {
                colorIndex++;
            }

            if (colorIndex === spectrum.length)
            {
                colorIndex = 0;
            }
            else if (colorIndex < 0)
            {
                colorIndex = spectrum.length - 1;
            }

            color = spectrum[colorIndex];

            light.color.setTo(color.r, color.g, color.b);

        });

        this.input.keyboard.on('keydown-A', () => {

            light.radius--;
            radius--;

        });

        this.input.keyboard.on('keydown-D', () => {

            light.radius++;
            radius++;

        });

        this.input.keyboard.on('keydown-W', () => {

            light.attenuation += 0.01;
            attenuation += 0.01;

        });

        this.input.keyboard.on('keydown-S', () => {

            light.attenuation -= 0.01;
            attenuation -= 0.01;

        });
    }
}

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

const game = new Phaser.Game(config);

Инициализация сцены и создание света

В методе create() сцены мы создаем текстовую подсказку и подготавливаем все необходимые переменные. Ключевой объект — light, создаваемый с помощью метода this.add.pointlight(). Он добавляется на сцену как игровой объект.

let radius = 128;
let intensity = 1;
let attenuation = 0.1;

let light = this.add.pointlight(400, 300, 0, radius, intensity);

Метод add.pointlight() принимает следующие аргументы: координаты X и Y, цвет (изначально 0), радиус и интенсивность. Цвет мы зададим отдельно. Также мы создаем массив цветов spectrum с помощью утилиты Phaser.Display.Color.ColorSpectrum(128), который содержит 128 цветов плавного спектра. Это удобно для циклического перебора оттенков.

Управление цветом и перемещение света

Цвет света задается через свойство light.color, которое является объектом типа Color. Мы используем метод setTo() для установки RGB-значений из текущего цвета в массиве spectrum.

light.color.setTo(color.r, color.g, color.b);

Перемещение света реализовано через обработчик события pointermove. Мы просто обновляем координаты `xиyобъектаlight`. Это позволяет перетаскивать источник света по сцене мышью.

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

Смена цвета происходит при прокрутке колесика мыши (wheel). В зависимости от направления прокрутки (deltaY) мы увеличиваем или уменьшаем индекс colorIndex и выбираем новый цвет из spectrum, после чего применяем его к свету.

Динамическое изменение радиуса и затухания

Радиус света — это расстояние, на которое распространяется его свечение. Им можно управлять через свойство light.radius. В примере радиус увеличивается и уменьшается при нажатии клавиш 'D' и 'A' соответственно.

this.input.keyboard.on('keydown-D', () => {
    light.radius++;
    radius++;
});

Затухание (attenuation) определяет, как быстро свет ослабевает от центра к краям. Чем больше значение, тем резче падает интенсивность. Затухание меняется клавишами 'W' и 'S'. Важно: значение attenuation нужно задавать явно при создании нового света (по клику), так как это свойство не копируется из переменной по умолчанию.

light.attenuation = attenuation;

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

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

this.input.on('pointerdown', pointer => {
    light = this.add.pointlight(pointer.x, pointer.y, 0, radius, intensity);
    light.attenuation = attenuation;
    light.color.setTo(color.r, color.g, color.b);
});

Обратите внимание: переменная light перезаписывается, и все последующие обработчики событий (движение, изменение радиуса) будут работать уже с новым источником. Если вам нужно управлять несколькими источниками одновременно, потребуется хранить их в массиве и обрабатывать все объекты в цикле.

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

Точечные источники света в Phaser 3 — это гибкий инструмент для создания динамического освещения. Вы научились создавать свет, менять его параметры в реальном времени и реагировать на действия игрока. Для экспериментов попробуйте привязать источник света к спрайту персонажа, создавая эффект фонарика. Или используйте массив источников для освещения нескольких объектов, меняя их цвет в зависимости от игровых событий (например, сигнализация). Поэкспериментируйте с комбинацией света и частиц (particle emitter) для создания магических эффектов.