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

В игровом движке Phaser геометрические объекты, такие как прямоугольники, часто используются для обработки столкновений, организации сеток и управления зонами. Статический метод `Phaser.Geom.Rectangle.CopyFrom` позволяет эффективно копировать свойства одного прямоугольника в другой, избегая создания новых объектов и экономя ресурсы. Эта статья на практическом примере покажет, как использовать этот метод для создания интерактивной сетки, где прямоугольники динамически меняют размер, следуя за курсором.

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

Живой запуск

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

Исходный код


class Example extends Phaser.Scene
{
    rectangles;
    pointerRect;
    graphics;

    create ()
    {
        this.graphics = this.add.graphics({ lineStyle: { color: 0x0000aa }, fillStyle: { color: 0x0000aa, alpha: 0.5 } });

        this.pointerRect = new Phaser.Geom.Rectangle(0, 0, 80, 60);

        this.rectangles = [];

        for (let x = 0; x < 10; x++)
        {
            this.rectangles[x] = [];

            for (let y = 0; y < 10; y++)
            {
                this.rectangles[x][y] = new Phaser.Geom.Rectangle(x * 80, y * 60, 80, 60);
            }
        }

        this.input.on('pointermove', pointer =>
        {
            const x = Math.floor(pointer.x / 80);
            const y = Math.floor(pointer.y / 60);

            this.pointerRect.setPosition(x * 80, y * 60);

            Phaser.Geom.Rectangle.CopyFrom(this.pointerRect, this.rectangles[x][y]);
        });
    }

    update ()
    {
        this.graphics.clear();

        this.graphics.fillRectShape(this.pointerRect);

        for (let x = 0; x < 10; x++)
        {
            for (let y = 0; y < 10; y++)
            {
                const rect = this.rectangles[x][y];

                if (rect.width > 10)
                {
                    rect.width *= 0.95;
                    rect.height *= 0.95;
                }

                this.graphics.strokeRectShape(rect);
            }
        }
    }
}

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

const game = new Phaser.Game(config);

Понимание геометрических объектов Phaser

В Phaser геометрические объекты, такие как Phaser.Geom.Rectangle, являются простыми контейнерами для данных (x, y, width, height). Они не отрисовываются автоматически и не имеют физики. Их основная роль — хранить координаты и размеры для вычислений.

В примере создаётся сетка из 10x10 прямоугольников. Каждый из них инициализируется с фиксированным размером 80x60 пикселей.

for (let x = 0; x < 10; x++)
{
    this.rectangles[x] = [];
    for (let y = 0; y < 10; y++)
    {
        this.rectangles[x][y] = new Phaser.Geom.Rectangle(x * 80, y * 60, 80, 60);
    }
}

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

Работа метода CopyFrom и обработка ввода

Метод Phaser.Geom.Rectangle.CopyFrom(sourceRect, destRect) копирует свойства `x,y,widthиheightиз исходного прямоугольника (sourceRect) в целевой (destRect`). Это мутирующая операция: она изменяет целевой объект, а не создаёт новый.

В примере обработчик события pointermove вычисляет, над какой ячейкой сетки находится курсор, позиционирует pointerRect в эту ячейку, а затем копирует его данные в соответствующий прямоугольник сетки.

this.input.on('pointermove', pointer =>
{
    const x = Math.floor(pointer.x / 80);
    const y = Math.floor(pointer.y / 60);
    this.pointerRect.setPosition(x * 80, y * 60);
    Phaser.Geom.Rectangle.CopyFrom(this.pointerRect, this.rectangles[x][y]);
});

Благодаря CopyFrom, прямоугольник в сетке мгновенно получает актуальные координаты курсорного прямоугольника. Это эффективнее, чем создавать новый экземпляр Rectangle каждый кадр.

Визуализация и анимация в методе update

Вся отрисовка происходит в методе update(). Сначала graphics.clear() очищает холст от предыдущего кадра. Затем заливается синим прямоугольник pointerRect.

this.graphics.clear();
this.graphics.fillRectShape(this.pointerRect);

Далее в двойном цикле происходит обход всех прямоугольников сетки. Если ширина прямоугольника больше 10 пикселей, она уменьшается на 5% каждый кадр, создавая эффект "сжатия".

if (rect.width > 10)
{
    rect.width *= 0.95;
    rect.height *= 0.95;
}

Затем каждый прямоугольник сетки обводится контуром с помощью strokeRectShape. Прямоугольник, в который только что скопировали данные (CopyFrom), на следующем кадре начнёт сжиматься снова, так как его размер был сброшен до 80x60.

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

Метод Phaser.Geom.Rectangle.CopyFrom — это простой и производительный инструмент для синхронизации состояния геометрических объектов. В рассмотренном примере он обеспечивает мгновенную реакцию сетки на движение курсора. Для экспериментов попробуйте: изменить логику сжатия (например, чтобы прямоугольники росли при наведении), использовать другие геометрические объекты (Circle, Triangle) с их методами копирования или применить CopyFrom для реализации простой системы выделения объектов (selection box) в стратегической игре.