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

При разработке игр часто возникает необходимость точно знать, где находятся границы игрового объекта на сцене — для проверки столкновений, определения видимости камеры или размещения UI-элементов. Phaser предоставляет простой метод `getBounds()`, возвращающий прямоугольную область (bounding box) спрайта или изображения. В этой статье мы разберем, как правильно работать с этим методом, учитывая влияние точки привязки (origin), масштаба и вращения, а также научимся визуализировать границы для отладки.

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

Живой запуск

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

Исходный код


class Example extends Phaser.Scene
{
    graphics;
    bounds3;
    bounds2;
    bounds1;
    image3;
    image2;
    image1;

    preload ()
    {
        this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
        this.load.image('eye', 'assets/pics/lance-overdose-loader-eye.png');
        this.load.image('disk', 'assets/sprites/copy-that-floppy.png');
        this.load.image('tetris', 'assets/sprites/tetrisblock1.png');
    }

    create ()
    {
        this.image1 = this.add.image(700, 200, 'eye');
        this.image2 = this.add.image(180, 180, 'tetris');
        this.image3 = this.add.image(400, 500, 'disk');

        this.image1.setOrigin(1);
        this.image2.setOrigin(0);
        this.image3.setOrigin(0.5);

        this.image3.setScale(0.5);

        this.graphics = this.add.graphics();

        this.bounds1 = this.image1.getBounds();
        this.bounds2 = this.image2.getBounds();
        this.bounds3 = this.image3.getBounds();

        this.tweens.add({

            targets: this.image3,
            duration: 2000,
            scaleX: 2,
            scaleY: 2,
            ease: 'Sine.easeInOut',
            repeat: -1,
            yoyo: true

        });
    }

    update ()
    {
        this.image1.rotation += 0.013;
        this.image2.rotation += 0.015;
        this.image3.rotation -= 0.010;

        this.bounds1 = this.image1.getBounds();
        this.bounds2 = this.image2.getBounds();
        this.bounds3 = this.image3.getBounds();

        this.graphics.clear();

        this.graphics.lineStyle(1, 0xff0000);
        this.graphics.strokeRectShape(this.bounds1);

        this.graphics.lineStyle(1, 0xffff00);
        this.graphics.strokeRectShape(this.bounds2);

        this.graphics.lineStyle(1, 0x00ff00);
        this.graphics.strokeRectShape(this.bounds3);
    }
}

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

const game = new Phaser.Game(config);

Что такое `getBounds()` и зачем он нужен?

Метод getBounds() объекта типа Phaser.GameObjects.Image (или любого другого игрового объекта) возвращает объект Phaser.Geom.Rectangle. Этот прямоугольник описывает область, которую объект занимает на сцене в мировых координатах, с учетом всех текущих трансформаций: позиции, масштаба, вращения и точки привязки (origin).

Это критически важно, потому что свойство `xиyобъекта указывают на его точку привязки, а не на верхний левый угол.getBounds()` дает нам абсолютные координаты реального занимаемого места, что является основой для многих игровых механик.

Подготовка сцены и настройка объектов

В методе preload() загружаются три изображения. В create() они добавляются на сцену с разными начальными координатами.

Ключевой момент — настройка точки привязки (origin) и масштаба. Это напрямую влияет на результат getBounds().

this.image1 = this.add.image(700, 200, 'eye');
this.image2 = this.add.image(180, 180, 'tetris');
this.image3 = this.add.image(400, 500, 'disk');

// Меняем точку привязки (по умолчанию 0.5, центр)
this.image1.setOrigin(1); // Привязка к правому нижнему углу изображения
this.image2.setOrigin(0); // Привязка к левому верхнему углу
this.image3.setOrigin(0.5); // Привязка к центру (значение по умолчанию)

// Меняем масштаб
this.image3.setScale(0.5);

Сразу после создания объектов мы получаем их начальные границы и сохраняем ссылки на эти прямоугольники в переменные bounds1, bounds2, bounds3.

this.bounds1 = this.image1.getBounds();
this.bounds2 = this.image2.getBounds();
this.bounds3 = this.image3.getBounds();

Также создается объект Graphics (this.graphics) для последующей отрисовки контуров.

Динамика и анимация границ

В примере объекты постоянно вращаются в методе update(), а image3 дополнительно анимируется с помощью твина, который циклически меняет его масштаб.

// Вращение объектов
this.image1.rotation += 0.013;
this.image2.rotation += 0.015;
this.image3.rotation -= 0.010;

// Твин для масштабирования (добавлен в create())
this.tweens.add({
    targets: this.image3,
    duration: 2000,
    scaleX: 2,
    scaleY: 2,
    ease: 'Sine.easeInOut',
    repeat: -1,
    yoyo: true
});

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

Визуализация границ для отладки

Самый наглядный способ убедиться, что getBounds() работает правильно — нарисовать эти границы. Для этого используется объект Graphics.

Важно: объект Graphics рисует в мировых координатах. Перед отрисовкой нового кадра мы очищаем старые линии с помощью clear().

this.graphics.clear();

// Рисуем прямоугольник для bounds1 красным цветом
this.graphics.lineStyle(1, 0xff0000);
this.graphics.strokeRectShape(this.bounds1);

// Рисуем прямоугольник для bounds2 желтым цветом
this.graphics.lineStyle(1, 0xffff00);
this.graphics.strokeRectShape(this.bounds2);

// Рисуем прямоугольник для bounds3 зеленым цветом
this.graphics.lineStyle(1, 0x00ff00);
this.graphics.strokeRectShape(this.bounds3);

Метод strokeRectShape() принимает объект Phaser.Geom.Rectangle и рисует его контур. Вы увидите, как прямоугольники точно охватывают вращающиеся и масштабирующиеся изображения, меняя свои размеры и положение.

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

Метод getBounds() — это мощный инструмент для работы с геометрией объектов в Phaser. Он избавляет разработчика от сложных ручных расчетов, учитывая все трансформации. Для экспериментов попробуйте

  1. Проверять пересечение границ объектов с помощью Phaser.Geom.Rectangle.Overlaps()
  2. Реализовать простую проверку на выход объекта за пределы камеры, используя camera.worldView и getBounds()
  3. Динамически менять origin объекта и наблюдать, как смещается его ограничивающая рамка