О чем этот пример
При работе с игровым интерфейсом, меню или диалогами часто возникает необходимость точно знать размеры текстового блока. Например, чтобы выровнять текст по центру кнопки, динамически создать рамку вокруг надписи или корректно расположить несколько текстовых элементов друг относительно друга. Встроенный в Phaser метод `getTextBounds()` для BitmapText предоставляет всю необходимую информацию о габаритах текста, учитывая его содержимое, шрифт и размер. Эта статья на практическом примере покажет, как получить точные размеры текста и визуализировать их, что станет основой для создания сложных и аккуратных UI-элементов в вашей игре.
Версия Phaser: код и демо в этой статье рассчитаны на Phaser 3.90.0.
Живой запуск
Ниже встроен рабочий билд примера. Оригинальный источник: GitHub.
Исходный код
class Example extends Phaser.Scene
{
constructor ()
{
super();
}
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');
this.load.bitmapFont('gothic', 'assets/fonts/bitmap/gothic.png', 'assets/fonts/bitmap/gothic.xml');
this.load.bitmapFont('hyper', 'assets/fonts/bitmap/hyperdrive.png', 'assets/fonts/bitmap/hyperdrive.xml');
}
create ()
{
this.graphics = this.add.graphics({ x: 0, y: 0, fillStyle: { color: 0xff00ff, alpha: 1 } });
const text1 = this.add.bitmapText(0, 0, 'atari', 'Welcome!', 70);
const text2 = this.add.bitmapText(0, 160, 'gothic', 'Welcome!', 40);
const text3 = this.add.bitmapText(0, 300, 'hyper', 'Terminator 2', 128);
this.bounds1 = text1.getTextBounds(true);
this.bounds2 = text2.getTextBounds(true);
this.bounds3 = text3.getTextBounds(true);
}
update ()
{
this.graphics.clear();
this.graphics.fillRect(this.bounds1.global.x, this.bounds1.global.y, this.bounds1.global.width, this.bounds1.global.height);
this.graphics.fillRect(this.bounds2.global.x, this.bounds2.global.y, this.bounds2.global.width, this.bounds2.global.height);
this.graphics.fillRect(this.bounds3.global.x, this.bounds3.global.y, this.bounds3.global.width, this.bounds3.global.height);
}
}
const config = {
type: Phaser.WEBGL,
parent: 'phaser-example',
scene: Example
};
const game = new Phaser.Game(config);
Загрузка растровых шрифтов и создание текста
Перед измерением текста его необходимо создать. В примере загружаются три разных растровых шрифта (bitmap fonts). Растровые шрифты — это предварительно отрисованные изображения символов, что обеспечивает высокую производительность и единообразие отображения на всех устройствах.
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');
this.load.bitmapFont('gothic', 'assets/fonts/bitmap/gothic.png', 'assets/fonts/bitmap/gothic.xml');
this.load.bitmapFont('hyper', 'assets/fonts/bitmap/hyperdrive.png', 'assets/fonts/bitmap/hyperdrive.xml');
}
После загрузки ресурсов в методе create() создаются три текстовых объекта с помощью this.add.bitmapText(). Каждый объект использует свой шрифт, размер и позицию по оси Y.
create ()
{
const text1 = this.add.bitmapText(0, 0, 'atari', 'Welcome!', 70);
const text2 = this.add.bitmapText(0, 160, 'gothic', 'Welcome!', 40);
const text3 = this.add.bitmapText(0, 300, 'hyper', 'Terminator 2', 128);
}
Получение границ текста с помощью getTextBounds
Ключевой метод в этом примере — getTextBounds(). Он вызывается для каждого объекта BitmapText и возвращает объект с подробными данными о границах текста.
this.bounds1 = text1.getTextBounds(true);
this.bounds2 = text2.getTextBounds(true);
this.bounds3 = text3.getTextBounds(true);
Аргумент true указывает, что метод должен рассчитать границы заново, что важно, если текст или его свойства могли измениться с момента последнего вызова. Возвращаемый объект содержит несколько свойств. В примере используется часть global, которая описывает итоговые, уже отмасштабированные границы текста в координатах игрового мира:
- global.x, global.y — координаты левого верхнего угла текстового блока.
- global.width, global.height — его ширина и высота.
Эти значения уже учитывают размер шрифта (переданный при создании текста), и их можно сразу использовать для отрисовки.
Визуализация границ через Graphics
Чтобы наглядно увидеть, какие именно области занимает текст, в примере используется объект Graphics. Это инструмент для программной отрисовки примитивов (прямоугольников, линий, кругов).
Сначала объект создается в create().
this.graphics = this.add.graphics({ x: 0, y: 0, fillStyle: { color: 0xff00ff, alpha: 1 } });
Затем, в методе update(), который вызывается каждый кадр, происходит отрисовка. Перед рисованием необходимо очистить холст от графики предыдущего кадра с помощью clear().
update ()
{
this.graphics.clear();
this.graphics.fillRect(this.bounds1.global.x, this.bounds1.global.y, this.bounds1.global.width, this.bounds1.global.height);
this.graphics.fillRect(this.bounds2.global.x, this.bounds2.global.y, this.bounds2.global.width, this.bounds2.global.height);
this.graphics.fillRect(this.bounds3.global.x, this.bounds3.global.y, this.bounds3.global.width, this.bounds3.global.height);
}
Метод fillRect() рисует залитый прямоугольник. В него передаются координаты и размеры, полученные из getTextBounds(). В результате вокруг каждого текстового блока появляется розовая (0xff00ff) рамка, точно его обводящая.
Практическое применение: центрирование и динамические UI
Получение точных размеров текста открывает множество возможностей для создания интерфейса.
**Центрирование текста в заданной области:** Зная ширину текста и ширину контейнера (например, кнопки), можно легко вычислить координату X для выравнивания по центру.
const buttonWidth = 300;
const textBounds = myText.getTextBounds(true);
const centeredX = (buttonWidth - textBounds.global.width) / 2;
myText.setX(centeredX);
**Динамическое создание фона:** Можно создать спрайт или нарисовать фигуру под текстом, размеры которой вычисляются на основе getTextBounds(), с добавлением отступов.
**Точное расположение элементов друг под другом:** Вычисляя высоту предыдущего текстового блока, можно автоматически рассчитывать позицию Y для следующего, создавая аккуратные списки или меню.
Использование global свойств гарантирует, что расчеты будут корректными даже если сам объект текста масштабируется или вращается.
Что попробовать дальше
Метод getTextBounds() — это мощный и простой инструмент для точного управления текстом в Phaser. Он снимает с разработчика груз ручных расчетов и догадок о размерах строк, позволяя создавать динамические, адаптивные и визуально выверенные интерфейсы.
Для экспериментов попробуйте:
1. Изменить текст в реальном времени (свойство text объекта) и пересчитывать его границы, чтобы анимированно изменять размер фоновой плашки.
2. Создать систему всплывающих подсказок, где размер окна подсказки зависит от длины текста внутри.
3. Реализовать выравнивание текста не только по левому краю, но и по правому или центру, используя полученную ширину.
