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

При разработке игр часто возникает задача динамически изменять игровое пространство — например, убирать платформы или создавать проходимые участки в стенах. В Phaser для этого есть удобный метод `setEmpty()` у геометрического объекта `Rectangle`. Эта статья покажет, как с его помощью создавать интерактивную сетку, где клик «стирает» ячейку, делая её пустой для отрисовки и потенциальных физических расчётов. Этот приём полезен для создания разрушаемых уровней, редакторов карт или интерактивных пазлов.

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

Живой запуск

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

Исходный код


class Example extends Phaser.Scene
{
    create ()
    {
        const graphics = this.add.graphics({ fillStyle: { color: 0x0000ff }, lineStyle: { color: 0x0000aa } });

        const rectangles = [];

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

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

            rectangles[x][y].setEmpty();

            redraw();
        });

        redraw();

        function redraw ()
        {
            graphics.clear();

            for (let x = 0; x < 10; x++)
            {
                for (let y = 0; y < 10; y++)
                {
                    graphics.fillRectShape(rectangles[x][y]);
                    graphics.strokeRectShape(rectangles[x][y]);
                }
            }
        }
    }
}

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

const game = new Phaser.Game(config);

Подготовка сцены и создание сетки прямоугольников

В методе create() сцены мы сначала создаём объект Graphics для рисования. Затем формируем двумерный массив rectangles, который будет хранить 100 объектов Phaser.Geom.Rectangle (10x10). Каждый прямоугольник имеет размер 80x60 пикселей и позиционируется с шагом по этим же значениям, образуя аккуратную сетку.

const graphics = this.add.graphics({ fillStyle: { color: 0x0000ff }, lineStyle: { color: 0x0000aa } });
const rectangles = [];

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

Обработка клика и вызов setEmpty()

Мы навешиваем обработчик события 'pointerdown' на сцену. При клике координаты курсора (pointer.x и pointer.y) преобразуются в индексы массива rectangles путём деления на размер ячейки с округлением вниз (Math.floor). Это позволяет найти прямоугольник, в который попал клик.

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

    rectangles[x][y].setEmpty();

    redraw();
});

Ключевой момент — вызов метода setEmpty() у найденного прямоугольника. Этот метод сбрасывает ширину и высоту объекта Rectangle в ноль, фактически делая его «пустым». После изменения состояния сетки мы вызываем функцию redraw() для обновления изображения.

Функция перерисовки и визуальный результат

Функция redraw() очищает холст graphics и заново рисует все прямоугольники из массива. Для отрисовки используются методы fillRectShape() (заливка) и strokeRectShape() (обводка).

function redraw ()
{
    graphics.clear();

    for (let x = 0; x < 10; x++)
    {
        for (let y = 0; y < 10; y++)
        {
            graphics.fillRectShape(rectangles[x][y]);
            graphics.strokeRectShape(rectangles[x][y]);
        }
    }
}

Важно понять: когда у прямоугольника вызван setEmpty(), его ширина и высота равны нулю. Поэтому методы fillRectShape() и strokeRectShape() для такого объекта ничего не нарисуют — ячейка визуально исчезнет с экрана. Однако сам объект Rectangle остаётся в массиве, просто в «нулевом» состоянии.

Зачем это нужно? Практическое применение

Метод setEmpty() — это не просто способ скрыть графику. В контексте игровой логики он может отмечать область как «несуществующую». Например, если вы используете Phaser.Physics.Arcade и проверяете столкновения игрока с прямоугольниками из этого массива, «пустой» прямоугольник (с нулевыми размерами) просто не будет участвовать в коллизиях. Это открывает возможности для: * **Динамического изменения уровня:** Удаление кирпичей, платформ или стен при выстреле или клике. * **Создания порталов или скрытых зон:** Область можно «открыть» и сделать проходимой. * **Построения простого редактора карт:** Где клик добавляет или убирает препятствие.

Помните, что setEmpty() — это метод геометрического объекта. Для полного удаления спрайта или физического тела из игры нужны другие подходы, например, destroy().

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

Метод setEmpty() у Phaser.Geom.Rectangle — это лёгкий способ перевести геометрическую область в «нулевое» состояние, что полезно для интерактивного управления игровым пространством. Для экспериментов попробуйте: изменить логику так, чтобы клик не стирал, а восстанавливал ячейку (используя setSize()); связать каждый прямоугольник с физическим телом (Arcade.Sprite) и отключать его физику при вызове setEmpty(); или реализовать «кисть» для закрашивания нескольких ячеек за один заход.