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

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

Версия 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.spritesheet('aliens', 'assets/sprites/bsquadron-enemies.png', { frameWidth: 192, frameHeight: 160 });
    }

    create ()
    {
        const graphics = this.add.graphics();

        graphics.fillStyle(0xffff00, 1);
        graphics.slice(400, 300, 200, Phaser.Math.DegToRad(340), Phaser.Math.DegToRad(20), true);
        graphics.fillPath();

        graphics.setInteractive(new Phaser.Geom.Circle(400, 300, 200), Phaser.Geom.Circle.Contains);

        graphics.on('pointerover', () =>
        {

            graphics.clear();
            graphics.fillStyle(0xff0000, 1);
            graphics.slice(400, 300, 200, Phaser.Math.DegToRad(340), Phaser.Math.DegToRad(20), true);
            graphics.fillPath();

        });

        graphics.on('pointerout', () =>
        {

            graphics.clear();
            graphics.fillStyle(0xffff00, 1);
            graphics.slice(400, 300, 200, Phaser.Math.DegToRad(340), Phaser.Math.DegToRad(20), true);
            graphics.fillPath();

        });
    }
}

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

const game = new Phaser.Game(config);

Создание и настройка объекта Graphics

В Phaser объект Graphics создается через фабричный метод сцены this.add.graphics(). Это ваш холст для рисования.

Перед началом рисования необходимо задать стиль заливки с помощью метода fillStyle(). Первый аргумент — цвет в шестнадцатеричном формате, второй — альфа-канал (прозрачность).

const graphics = this.add.graphics();
graphics.fillStyle(0xffff00, 1);

После настройки стиля можно приступать к определению формы. В нашем примере используется метод slice(), который рисует сектор круга (как кусок пирога или пиццы). Для его отображения на экране необходимо завершить команду вызовом fillPath().

Рисование фигуры: метод slice()

Метод slice() рисует сектор (срез) круга. Его параметры определяют положение, размер и углы.

graphics.slice(400, 300, 200, Phaser.Math.DegToRad(340), Phaser.Math.DegToRad(20), true);
graphics.fillPath();

Разберем аргументы по порядку: 1. **400, 300**: координаты X и Y центра круга. 2. **200**: радиус круга. 3. **Phaser.Math.DegToRad(340)**: начальный угол среза. Поскольку Phaser работает с радианами, мы используем вспомогательную функцию DegToRad() для конвертации 340 градусов. 4. **Phaser.Math.DegToRad(20)**: конечный угол среза (20 градусов). Фигура будет нарисована от 340° до 20° по часовой стрелке. 5. **true**: флаг, указывающий, следует ли рисовать сектор по часовой стрелке.

Вызов fillPath() применяет ранее заданный стиль заливки (fillStyle) и отрисовывает фигуру на экране.

Добавление интерактивности: setInteractive

Чтобы объект Graphics реагировал на события мыши, ему нужно назначить зону взаимодействия с помощью setInteractive(). В примере используется геометрическая форма Phaser.Geom.Circle и функция проверки Phaser.Geom.Circle.Contains.

graphics.setInteractive(new Phaser.Geom.Circle(400, 300, 200), Phaser.Geom.Circle.Contains);

Этот код создает невидимую область взаимодействия в форме круга с центром в (400, 300) и радиусом 200 пикселей. События мыши (pointerover, pointerout) будут срабатывать, только когда курсор находится внутри этого круга, а не строго внутри нарисованного желтого сектора. Это упрощает логику взаимодействия для пользователя.

Обработка событий и динамическое перерисовывание

Объект Graphics может прослушивать стандартные события ввода. В примере обрабатываются pointerover (курсор над объектом) и pointerout (курсор покинул объект).

Ключевой момент: перед изменением внешнего вида графику нужно очистить с помощью метода clear(). Иначе новые фигуры будут рисоваться поверх старых.

graphics.on('pointerover', () => {
    graphics.clear();
    graphics.fillStyle(0xff0000, 1);
    graphics.slice(400, 300, 200, Phaser.Math.DegToRad(340), Phaser.Math.DegToRad(20), true);
    graphics.fillPath();
});

При наведении курсора (pointerover) фигура очищается, стиль заливки меняется на красный, и тот же самый сектор перерисовывается. При уходе курсора (pointerout) происходит обратный процесс: очистка и отрисовка сектора с исходным желтым цветом.

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

Объект Graphics предоставляет гибкий API для создания и управления векторной графикой прямо в игровом цикле. Вы научились рисовать фигуры, назначать им зоны взаимодействия и динамически менять их в ответ на действия игрока. Для экспериментов попробуйте изменить форму: используйте fillRect() или fillCircle(). Добавьте анимацию плавного изменения цвета или радиуса внутри обработчиков событий. Или создайте сложный составной UI-элемент, собранный из нескольких графических объектов.