О чем этот пример
При разработке игр часто возникает необходимость точно знать, где находятся границы игрового объекта на сцене — для проверки столкновений, определения видимости камеры или размещения 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. Он избавляет разработчика от сложных ручных расчетов, учитывая все трансформации. Для экспериментов попробуйте
- Проверять пересечение границ объектов с помощью
Phaser.Geom.Rectangle.Overlaps() - Реализовать простую проверку на выход объекта за пределы камеры, используя
camera.worldViewиgetBounds() - Динамически менять
originобъекта и наблюдать, как смещается его ограничивающая рамка
