О чем этот пример
При создании игр с динамическим интерфейсом или анимированным текстом часто возникает задача точного позиционирования и обработки столкновений. Стандартные методы получения размеров игрового объекта могут не учитывать текущий масштаб. В этой статье мы разберем, как корректно получать реальные, масштабированные границы объекта BitmapText в Phaser 3, что особенно полезно для выравнивания, проверки нажатий или отрисовки рамок вокруг текста.
Версия Phaser: код и демо в этой статье рассчитаны на Phaser 3.90.0.
Живой запуск
Ниже встроен рабочий билд примера. Оригинальный источник: GitHub.
Исходный код
class Example extends Phaser.Scene
{
constructor ()
{
super();
this.string = 'Phaser 3\nBitmapText\nScaling\nwith bounds';
}
preload ()
{
this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
this.load.bitmapFont('atari', 'assets/fonts/bitmap/atari-smooth.png', 'assets/fonts/bitmap/atari-smooth.xml');
}
create ()
{
this.text = this.add.bitmapText(0, 0, 'atari', this.string)
.setFontSize(32);
this.graphics = this.add.graphics({ x: 0, y: 0, lineStyle: { thickness: 1, color: 0xffff00, alpha: 1 } });
this.tweens.add({
targets: this.text,
duration: 4000,
scaleX: 2,
ease: 'Quad.easeInOut',
repeat: -1,
yoyo: true
});
this.tweens.add({
targets: this.text,
duration: 2000,
scaleY: 4,
ease: 'Quad.easeInOut',
repeat: -1,
yoyo: true
});
}
update ()
{
this.text.setText(this.string + '\nScale X: ' + this.text.scaleX.toFixed(4));
const bounds = this.text.getTextBounds();
this.graphics.clear();
this.graphics.strokeRect(bounds.global.x, bounds.global.y, bounds.global.width, bounds.global.height);
}
}
const config = {
type: Phaser.WEBGL,
parent: 'phaser-example',
scene: Example
};
const game = new Phaser.Game(config);
Создание и анимация BitmapText
В примере создается сцена с объектом BitmapText. Загружается растровый шрифт, после чего текст добавляется на сцену с начальным размером 32 пикселя.
Особенность примера — применение двух независимых твинов для анимации масштабирования по осям X и Y с разной длительностью и поведением 'yo-yo' (повтор туда-обратно). Это приводит к постоянному и плавному изменению пропорций текста.
this.text = this.add.bitmapText(0, 0, 'atari', this.string).setFontSize(32);
this.tweens.add({
targets: this.text,
duration: 4000,
scaleX: 2,
ease: 'Quad.easeInOut',
repeat: -1,
yoyo: true
});
Метод getTextBounds() — ключ к решению
Свойства width и height объекта BitmapText часто хранят исходные, не масштабированные размеры. Для получения актуальных размеров с учетом текущего scaleX, scaleY, угла поворота и других трансформаций используется метод getTextBounds().
Этот метод возвращает объект bounds с комплексной информацией. Наиболее полезны для практического использования поля global, которые содержат мировые координаты и размеры уже трансформированного текстового блока.
const bounds = this.text.getTextBounds();
// bounds.global содержит: x, y, width, height
Визуализация границ и обновление в реальном времени
Чтобы наглядно видеть, как изменяются реальные границы текста, в примере используется объект Graphics. В функции update(), которая вызывается на каждом кадре, выполняются три действия:
1. Обновляется содержимое текста, чтобы вывести в нем текущее значение масштаба по X.
2. Получаются актуальные границы через getTextBounds().
3. Старая графика очищается, и поверх текста рисуется новый желтый прямоугольник (strokeRect) по рассчитанным координатам и размерам.
update ()
{
this.text.setText(this.string + '\nScale X: ' + this.text.scaleX.toFixed(4));
const bounds = this.text.getTextBounds();
this.graphics.clear();
this.graphics.strokeRect(bounds.global.x, bounds.global.y, bounds.global.width, bounds.global.height);
}
Практическое применение
Получение масштабированных границ — это не только для отладки. Эта техника незаменима в реальных проектах: * **Точное выравнивание:** Для центрирования текста, который меняет размер, или размещения других элементов относительно его текущих границ. * **Кастомизация попаданий (Hit Area):** Чтобы область нажатия на текст соответствовала его видимому масштабированному виду, а не исходному прямоугольнику. * **Динамический UI:** При создании интерфейсов, где текстовые кнопки или подсказки могут анимировано увеличиваться или уменьшаться.
// Пример: проверка, находится ли курсор в границах масштабированного текста
if (bounds.global.contains(pointer.x, pointer.y)) {
// Действие при наведении
}
Что попробовать дальше
Использование getTextBounds().global — правильный способ работы с размерами BitmapText в динамических сценах. Для экспериментов попробуйте привязать к этим границам другие объекты (например, частицы), создать эффект «подсветки» при наведении или реализовать систему всплывающих подсказок, размер которых адаптируется под изменяющийся текст.
