разработка игр, программирование, сценарии, графика и музыка

English По-русски

Генерация растровых шрифтов в играх

Я использую растровые шрифты во всех своих играх. Это единственный метод отображения текста, который поддерживается моим движком, потому что он быстро обрабатывается видеокартой и требует мало памяти.

Растровые шрифты — это заранее нарисованный набор символов на текстуре, которая потом "режется" на кусочки для составления слов на экране.

Приключения Шерлока Холмса и доктора Ватсона: Собака Баскервилей (1981, реж. Игорь Масленников)
Приключения Шерлока Холмса и доктора Ватсона: Собака Баскервилей (1981, реж. Игорь Масленников)

Текстура, на которой рисуются все нужные символы, называется атласом.

Атлас обычно сопровождается текстовым файлом, в котором описана позиция и размер каждого символа, а также дополнительная информация о буквенных интервалах, кернинге, и других деталях.

Атлас растрового шрифта для отладки, используемого в Speebot, Phantom Path и Pilie Pals
Атлас растрового шрифта для отладки, используемого в Speebot, Phantom Path и Pilie Pals

Такой приём используется в компьютерах давно. Его относительно просто реализовать, и он хорошо вписывается в работу с видеокартой. Видеокарта получает от программы всего одну текстуру, которая хранится в памяти графического процессора, а для текстовых полей создаётся геометрия, которая обновляется только тогда, когда нужно поменять текст.

Таким образом можно быстро отображать большое количество динамического текста, и не надо задумываться о производительности.

Так как атлас — это просто картинка, то к буквам можно запросто добавить разные эффекты в графическом редакторе: тени, контуры, градиенты, и т.д. Такие эффекты никак не повлияют на производительность, потому что они "запекаются" в текстуре.

Однако, у такого подхода есть несколько больших минусов.

  • Растровые шрифты плохо масштабируются. Для каждого размера шрифта нужно создать отдельный атлас.
  • Можно использовать только те символы, которые есть в атласе. Если требуется добавить поддержку нового символа, то придётся обновлять все существующие атласы.
  • В некоторых языках десятки тысяч символов. Для поддержки отдельных языков нужно создавать отдельные атласы, а также экономить место на текстуре — включать в атлас только те символы, которые действительно используются в игре.

Если, например, в игре используется 2 стиля шрифта, 5 размеров текста и поддерживается 3 языка, то выходит, что необходимо создать 30 атласов. Если вдруг понадобится добавить новый символ (например, ©), то надо будет обновлять все 30 атласов. Это число растёт с добавлением новых стилей, размеров и языков. Подготовка атласов может занять очень много времени.

Другой вариант — использовать векторные шрифты. Для таких нужен всего один исходный файл, в котором содержится векторная информация о всех символах. Для использования требуется некая библиотека, способная рисовать векторную графику на текстуру.

Но и здесь есть большие минусы:

  • Рисовать векторные буквы — слишком медленно. Программа должна вычислить и отобразить каждый пиксель по формулам. Кроме того, это чаще всего происходит на процессоре.
  • Каждый раз, когда нужно обновить текстовое поле, создаётся новая текстура, которая посылается на видеокарту для замены старой. Если текстовое поле обновляется каждый кадр, то Вы очень быстро столкнётесь с проблемами в производительности и использовании памяти.

Я хочу продолжать использовать растровые шрифты из-за их хорошей производительности, но я также хочу иметь гибкость и простоту использования векторных шрифтов, потому что мне не нравится вручную создавать атласы. Поэтому, для экономии времени и сил, я решил объединить два подхода в один.

Идея в том, что движок может использовать векторные шрифты, но только для автоматической генерации растровых шрифтов.

Игра загружает файл шрифта, читает его, использует векторную библиотеку для отображения каждого символа на текстуре, сохраняет в памяти информацию о позициях и буквенном кернинге — и растровый шрифт готов. Этот процесс повторяется для каждого стиля, размера и языка.

Весь внутренний код, который уже используется для отображения растровых шрифтов, остаётся неизменным. Следовательно, производительность не страдает. Но теперь вместо создания атласов вручную, я просто обновляю текстовые файлы для добавления поддержки новых стилей или языков.

Например, так выглядит файл, в котором описаны стили для английского языка:

{
	"primary": {
		"glyphs": "QWERTYUIOPASDFGHJKLZXCVBNMqwertyuiopasdfghjklzxcvbnm!1234567890+-,.?!:()'\"#& ",
		"font": "PTSans-Regular.ttf"
	},
	"secondary": {
		"glyphs": "QWERTYUIOPASDFGHJKLZXCVBNMqwertyuiopasdfghjklzxcvbnm!1234567890+-,.?!:()'\"#& ",
		"font": "PTSans-Italic.ttf"
	}
}

Похожие файлы создаются для других языков.

В коде мне нужно только указать стиль и размер текстового поля, и движок автоматически создаёт нужный атлас. Если такой атлас уже был создан, то он берётся из памяти.

textField = BitmapTextField.fromStyle("primary", 24);
textField.setText("As you value your life or your reason keep away from the moor");

Эта новая система будет использоваться в моей следующей игре. Файлы описания стилей, файлы шрифтов и переводов будут доступны в папке игры. Поэтому будет возможность создавать моды локализаций для официально неподдерживаемых языков.

Следующая статья

Игра Пайли теперь на русском

Подписаться

Получайте уведомления о новых статьях, чтобы:

Следить за процессом разработки моей следующей игры.

Читать статьи об искусстве и технологиях создания игр и движков.

Получать новости об изменениях в моих играх.

Подписка бесплатная, просто нажмите на кнопку!