О чем этот пример
При разработке игр часто возникает необходимость точно знать, где находятся границы спрайта или изображения. Это критически важно для проверки столкновений, позиционирования интерфейса или создания динамических эффектов. В Phaser для этого существует мощный метод `getBounds()`. В этой статье мы разберем на практическом примере, как использовать этот метод для отслеживания углов вращающегося изображения с помощью маркеров.
Версия Phaser: код и демо в этой статье рассчитаны на Phaser 3.90.0.
Живой запуск
Ниже встроен рабочий билд примера. Оригинальный источник: GitHub.
Исходный код
class Example extends Phaser.Scene
{
rect;
bottomRight;
bottomLeft;
topRight;
topLeft;
image;
preload ()
{
this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
this.load.image('einstein', 'assets/pics/ra-einstein.png');
this.load.image('ball', 'assets/sprites/blue_ball.png');
}
create ()
{
this.image = this.add.image(400, 300, 'einstein');
this.topLeft = this.add.image(400,300, 'ball');
this.topRight = this.add.image(400,300, 'ball');
this.bottomLeft = this.add.image(400,300, 'ball');
this.bottomRight = this.add.image(400,300, 'ball');
this.image.setScale(0.5,0.5);
this.rect = this.image.getBounds();
this.topLeft.setPosition(this.rect.x,this.rect.y);
this.topRight.setPosition(this.rect.x + this.rect.width, this.rect.y);
this.bottomLeft.setPosition(this.rect.x, this.rect.y + this.rect.height);
this.bottomRight.setPosition(this.rect.x + this.rect.width, this.rect.y + this.rect.height);
}
update ()
{
this.image.rotation += 0.01;
this.rect = this.image.getBounds();
this.topLeft.setPosition(this.rect.x,this.rect.y);
this.topRight.setPosition(this.rect.x + this.rect.width,this.rect.y);
this.bottomLeft.setPosition(this.rect.x,this.rect.y + this.rect.height);
this.bottomRight.setPosition(this.rect.x + this.rect.width,this.rect.y + this.rect.height);
}
}
const config = {
type: Phaser.WEBGL,
width: 800,
height: 600,
backgroundColor: '#2d2d2d',
parent: 'phaser-example',
scene: Example
};
// var line;
const game = new Phaser.Game(config);
Что делает метод getBounds()?
Метод getBounds() возвращает прямоугольник (объект типа Phaser.Geom.Rectangle), который описывает мировые границы игрового объекта. Этот прямоугольник учитывает положение (`x,y), масштаб (scaleX,scaleY) и поворот (rotation) объекта. Его свойстваx,y,widthиheight` позволяют точно определить область, которую объект занимает на экране.
Это особенно полезно для объектов, которые вращаются или масштабируются в реальном времени, так как их визуальные границы не совпадают с исходными размерами текстуры.
// Получение границ изображения как прямоугольника
this.rect = this.image.getBounds();
Подготовка сцены и создание объектов
В примере создается сцена с одним основным изображением (Эйнштейн) и четырьмя спрайтами (синие шары), которые будут служить маркерами углов. Ключевой момент: все шары изначально создаются в одной точке — центре изображения. Их истинное положение будет вычислено позже на основе границ.
Обратите внимание, что изображение сразу масштабируется в два раза. Метод getBounds() учтет это изменение.
preload ()
{
this.load.image('einstein', 'assets/pics/ra-einstein.png');
this.load.image('ball', 'assets/sprites/blue_ball.png');
}
create ()
{
// Создание основного изображения и маркеров
this.image = this.add.image(400, 300, 'einstein');
this.topLeft = this.add.image(400,300, 'ball');
this.topRight = this.add.image(400,300, 'ball');
this.bottomLeft = this.add.image(400,300, 'ball');
this.bottomRight = this.add.image(400,300, 'ball');
// Масштабирование основного изображения
this.image.setScale(0.5,0.5);
}
Вычисление и визуализация углов
В функции create() происходит первичная расстановка маркеров. Мы получаем прямоугольник границ с помощью this.image.getBounds() и используем его свойства для расчета координат каждого угла.
* topLeft (левый верхний): (rect.x, rect.y)
* topRight (правый верхний): (rect.x + rect.width, rect.y)
* bottomLeft (левый нижний): (rect.x, rect.y + rect.height)
* bottomRight (правый нижний): (rect.x + rect.width, rect.y + rect.height)
Таким образом, шары "привязываются" к визуальным углам изображения, а не к его центру.
// Получаем актуальные границы
this.rect = this.image.getBounds();
// Позиционируем маркеры по углам
this.topLeft.setPosition(this.rect.x,this.rect.y);
this.topRight.setPosition(this.rect.x + this.rect.width, this.rect.y);
this.bottomLeft.setPosition(this.rect.x, this.rect.y + this.rect.height);
this.bottomRight.setPosition(this.rect.x + this.rect.width, this.rect.y + this.rect.height);
Динамическое обновление границ
Вся магия происходит в функции update(), которая выполняется каждый кадр. Изображение медленно вращается (this.image.rotation += 0.01). При повороте его мировые границы меняются.
Поэтому мы должны постоянно пересчитывать прямоугольник this.rect, снова вызывая this.image.getBounds(). После этого позиции маркеров обновляются по тем же формулам. В результате синие шары всегда точно отмечают углы вращающегося и масштабированного изображения, наглядно демонстрируя работу метода.
update ()
{
// Вращаем основное изображение
this.image.rotation += 0.01;
// КРИТИЧЕСКИ ВАЖНО: Получаем ОБНОВЛЕННЫЕ границы после поворота
this.rect = this.image.getBounds();
// Обновляем позиции маркеров на основе новых границ
this.topLeft.setPosition(this.rect.x,this.rect.y);
this.topRight.setPosition(this.rect.x + this.rect.width,this.rect.y);
this.bottomLeft.setPosition(this.rect.x,this.rect.y + this.rect.height);
this.bottomRight.setPosition(this.rect.x + this.rect.width,this.rect.y + this.rect.height);
}
Что попробовать дальше
Метод getBounds() — это ваш надежный способ получить точные мировые координаты любого игрового объекта в Phaser, независимо от его трансформаций. Он незаменим для реализации точных коллизий, привязки элементов интерфейса к объектам или создания сложных визуальных эффектов.
**Идеи для экспериментов:**
1. Попробуйте анимировать не только вращение, но и масштаб (scale) или положение (`x,y`) изображения и понаблюдайте за поведением маркеров.
2. Используйте полученный прямоугольник rect для отрисовки дебажного контура вокруг объекта с помощью this.add.graphics().
3. Реализуйте простую проверку столкновения "курсор-объект", используя getBounds() и метод contains объекта Phaser.Geom.Rectangle.
