О чем этот пример
Отображение текста в играх может стать узким местом для производительности, особенно при использовании системных шрифтов. Phaser предлагает мощное решение — BitmapText (растровые шрифты). Этот метод использует заранее отрендеренные изображения символов, что позволяет выводить текст на экран практически без затрат ресурсов процессора на растеризацию. В этой статье мы разберем пример загрузки нескольких растровых шрифтов и их использования для статического и динамического текста. Вы узнаете, как подготовить ресурсы, создать текстовые объекты и обновлять их содержимое в реальном времени, что идеально подходит для счетчиков очков, таймеров или диалоговых окон.
Версия Phaser: код и демо в этой статье рассчитаны на Phaser 3.90.0.
Живой запуск
Ниже встроен рабочий билд примера. Оригинальный источник: GitHub.
Исходный код
let value = 0;
class Example extends Phaser.Scene
{
constructor ()
{
super();
}
preload ()
{
this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
this.load.bitmapFont('desyrel', 'assets/fonts/bitmap/desyrel.png', 'assets/fonts/bitmap/desyrel.xml');
this.load.bitmapFont('desyrel-pink', 'assets/fonts/bitmap/desyrel-pink.png', 'assets/fonts/bitmap/desyrel-pink.xml');
this.load.bitmapFont('shortStack', 'assets/fonts/bitmap/shortStack.png', 'assets/fonts/bitmap/shortStack.xml');
}
create ()
{
const b = this.add.bitmapText(0, 0, 'desyrel', 16.34);
this.add.bitmapText(0, 200, 'desyrel-pink', 'Excepteur sint occaecat\ncupidatat non proident');
this.add.bitmapText(0, 400, 'shortStack', 'Phaser BitmapText');
this.dynamic = this.add.bitmapText(0, 500, 'desyrel', '');
}
update ()
{
this.dynamic.text = 'value: ' + value.toFixed(2);
value += 0.01;
}
}
const config = {
type: Phaser.WEBGL,
parent: 'phaser-example',
scene: Example
};
const game = new Phaser.Game(config);
Загрузка растровых шрифтов
Перед использованием растрового шрифта его необходимо загрузить. Растровый шрифт состоит из двух файлов: изображения (.png) со всеми символами и файла описания (обычно .xml или .fnt), который содержит данные о положении каждого глифа (символа) на изображении.
В методе preload() сцены мы используем this.load.bitmapFont(). Первый аргумент — это уникальный ключ (ключ ассета), по которому мы будем обращаться к шрифту в коде. Второй и третий аргументы — пути к файлам изображения и данных соответственно.
this.load.bitmapFont('desyrel', 'assets/fonts/bitmap/desyrel.png', 'assets/fonts/bitmap/desyrel.xml');
this.load.bitmapFont('desyrel-pink', 'assets/fonts/bitmap/desyrel-pink.png', 'assets/fonts/bitmap/desyrel-pink.xml');
this.load.bitmapFont('shortStack', 'assets/fonts/bitmap/shortStack.png', 'assets/fonts/bitmap/shortStack.xml');
В примере загружаются три разных шрифта, что демонстрирует возможность использования в одной сцене нескольких стилей текста.
Создание статического текста
После загрузки ресурсов в методе create() мы создаем объекты растрового текста. Основной метод для этого — this.add.bitmapText().
Параметры метода:
1. Координата X.
2. Координата Y.
3. Ключ шрифта, загруженного в preload().
4. Строка текста для отображения. Это может быть многострочный текст, для чего используются символы переноса строки \n.
5. Размер шрифта (опционально). Если не указан, используется размер по умолчанию из файла данных шрифта.
const b = this.add.bitmapText(0, 0, 'desyrel', 16.34);
this.add.bitmapText(0, 200, 'desyrel-pink', 'Excepteur sint occaecat\ncupidatat non proident');
this.add.bitmapText(0, 400, 'shortStack', 'Phaser BitmapText');
Первая строка создает объект текста с числовым значением в качестве строки. Вторая строка показывает пример многострочного текста. Третья строка использует шрифт с другим визуальным стилем. Эти объекты являются статическими — их текст задается один раз и не меняется.
Динамическое обновление текста
Часто в игре текст должен меняться: счет, время, название уровня. Для этого нужно сохранить ссылку на объект BitmapText в переменную класса, чтобы иметь доступ к нему в других методах сцены, например, в update().
В методе create() последним создается объект с пустым текстом, и ссылка на него сохраняется в свойство this.dynamic.
this.dynamic = this.add.bitmapText(0, 500, 'desyrel', '');
Теперь в методе update(), который вызывается на каждом кадре игры, мы можем изменять свойство .text этого объекта. В примере используется глобальная переменная value, которая увеличивается, и ее значение форматируется до двух знаков после запятой с помощью toFixed(2).
update ()
{
this.dynamic.text = 'value: ' + value.toFixed(2);
value += 0.01;
}
Таким образом, текст в нижней части экрана будет плавно увеличиваться, демонстрируя плавное динамическое обновление. Это основа для создания любых игровых счетчиков.
Конфигурация и запуск игры
Код примера завершается стандартной для Phaser 3 конфигурацией и созданием экземпляра игры. Ключевой момент — в конфиге указан type: Phaser.WEBGL. Растровые шрифты могут работать и в режиме Phaser.CANVAS, но для максимальной производительности рекомендуется использовать WebGL.
const config = {
type: Phaser.WEBGL,
parent: 'phaser-example',
scene: Example
};
const game = new Phaser.Game(config);
Свойство parent указывает на id HTML-элемента, в который будет встроен canvas игры. В данном случае это элемент с id="phaser-example".
Что попробовать дальше
BitmapText — это эффективный и гибкий инструмент для работы с текстом в Phaser. Он незаменим для проектов, где критична производительность или требуется специфичный стилизованный шрифт. Для экспериментов попробуйте: анимировать положение или масштаб текстового объекта в update(); изменять цвет оттенка (tint) динамического текста в зависимости от его значения; реализовать эффект печатающегося текста (typewriter effect), посимвольно добавляя строку в свойство .text с использованием таймера событий this.time.addEvent.
