О чем этот пример
В игровой разработке часто требуется знать точные границы игровых объектов для обработки столкновений, позиционирования UI или динамических эффектов. Метод `getBounds()` в Phaser 3 — это мощный инструмент, который возвращает прямоугольник, описывающий мировые координаты объекта с учётом его трансформаций (позиции, масштаба, поворота). В этой статье мы разберем практический пример, который наглядно демонстрирует, как работает этот метод с изображениями внутри контейнера, и как визуализировать эти границы в реальном времени.
Версия 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);
const container = this.add.container(100, 0, [ this.image1, this.image2, this.image3 ]).setAngle(20);
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);
Подготовка сцены и загрузка ресурсов
Вся логика примера находится внутри класса сцены Example. В методе preload() мы загружаем три текстуры с помощью this.load.image(). Обратите внимание на использование setBaseURL() — это удобный способ указать базовый путь для всех загружаемых ресурсов.
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.add.image) с разными начальными позициями. Ключевой момент — установка точки вращения (origin). Для image1 установлен origin в (1, 1) — правый нижний угол, для image2 — (0, 0) — левый верхний угол, а для image3 — (0.5, 0.5) — центр. Это повлияет на их вращение и расчёт границ. Объект image3 также сразу масштабируется вполовину.
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.add.container). Контейнер позиционируется в точке (100, 0) и поворачивается на 20 градусов (setAngle(20)). Важно понимать, что контейнер применяет свои трансформации ко всем своим дочерним элементам. Сразу после создания объектов мы впервые получаем их границы с помощью метода getBounds() и сохраняем их в свойствах bounds1, bounds2, bounds3. Для image3 также создается бесконечная анимация пульсации масштаба с помощью this.tweens.add.
const container = this.add.container(100, 0, [ this.image1, this.image2, this.image3 ]).setAngle(20);
this.graphics = this.add.graphics();
this.bounds1 = this.image1.getBounds();
this.bounds2 = this.image2.getBounds();
this.bounds3 = this.image3.getBounds();
// Tween для масштабирования image3
this.tweens.add({
targets: this.image3,
duration: 2000,
scaleX: 2,
scaleY: 2,
ease: 'Sine.easeInOut',
repeat: -1,
yoyo: true
});
Визуализация границ в реальном времени
Сердце примера — метод update(), который вызывается каждый кадр. Здесь происходит три вещи: объекты вращаются с разной скоростью, их границы пересчитываются через getBounds(), и эти границы отрисовываются с помощью графического объекта Graphics. this.graphics.clear() стирает рисунок предыдущего кадра. Затем для каждого объекта устанавливается стиль линии (lineStyle) разного цвета и рисуется прямоугольник (strokeRectShape) поверх изображения, используя рассчитанные границы.
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);
}
Что попробовать дальше
Метод getBounds() — это основа для многих игровых механик в Phaser 3. Как мы увидели, он корректно учитывает все трансформации: позицию, масштаб, поворот объекта, а также трансформации его родительского контейнера. Это делает его идеальным для проверки пересечений «по bounding box» или для точного позиционирования элементов интерфейса относительно игровых объектов. Для экспериментов попробуйте: изменить origin у объектов и посмотреть, как «прыгают» границы; добавить в контейнер скейл или сдвиг; использовать полученные границы для простой проверки столкновения между image1 и image2 с помощью Phaser.Geom.Rectangle.Overlaps.
