Читабельность кода вышла из чата
Наш опыт разработки шрифтов и локализации игры
Привет всем! Хочется немного поделиться своим опытом по части разработки, интеграции шрифта и локализации нашей игры, которую мы разрабатываем на Unity.
Поиски бесплатного шрифта
Месяцев 7 назад мне пришлось работать над шрифтом. Ранее не доводилось работать со шрифтами (в шрифтах не специалист), так что создавал всё путем поиска наиболее подходящих, на мой взгляд, образцов. За основу нашего шрифта был взят шрифт, которым написано слово "МОЛОКО":
Далее проводились бесконечные попытки начертания глифов в тетради в клетку и их перенос в растровый формат. Перенос глифов в растровый формат - это моя большая ошибка. Правильнее было бы сразу все делать в векторе. Ниже прилагаю сохранившийся материал из процесса работы над некоторыми глифами (первые наброски):
Финальные тесты в Unity:
Перенос шрифта с бумаги в png-файл:
Пример стилизованного символа "Q" :
Так выглядят текстуры наших финальных кириллических и латинских глифов/символов (растровый вариант):
Поддержка языков, проблемы
Предполагалось, что система локализации должна быть максимально гибкой. То есть должна быть возможность добавления новых шрифтов "без проблем".
Разработка шрифта стала для меня большим проектом. Кроме разработки и переноса шрифта в старой системе шрифтов Unity, нужно было вручную разметить участки текстуры, которые отвечали за символы:
Позже возникла необходимость добавить немецкий язык. Пришлось вспомнить о том, как сложно создавать растровые шрифты, а потом настраивать их развёртки. Вся эта работа превращалась в бесконечный ад, который склонял к использованию чего угодно, помимо имеющейся системы шрифтов.
Позже выяснилось, что ручной подход настройки отображения шрифтов изначально был негибким, не учитывали кучу особенностей символов. Основная особенность - в разных алфавитах разное количество букв. А ещё бывают весьма экзотические буквы, которые либо значительно сокращают место на карте текстуры шрифта, либо требуют особой настройки отображения из-за отличающихся габаритных размеров. Например, лигатуры и "умлауты (umlauts)":
Лигатуры - это символы, которые состоят из нескольких склеенных символов (как на рис. выше).
К счастью, в Unity появился бесплатный TextMesh Pro. Это очень хороший плагин, который автоматизирует процесс переноса шрифтов из ttf-формата в текстуру с настроенными параметрами отображения. Часы работы по настройке отображения каждого глифа, задания расстояний и прочего сократились до пары щелчков мышкой. Фантастика!
Зачем нам свой шрифт, когда можно взять бесплатный?
На самом деле, зачем он и для чего? Очень часто у многих встаёт такой вопрос. В сети нередко возникают споры между дизайнерами и остальными разработчиками по поводу того, что на шрифтах можно здорово сэкономить.
К слову, в сети очень часто высказываются в пользу минимизации времени работы над шрифтами, так как многие предполагают, что шрифт вносит незначительный вклад в восприятие игры и в геймплей в целом. Часто предлагают: "не заморачиваться и использовать что-то попроще".
На самом деле есть доля правды в отсутствии необходимости проработки шрифтов. Согласно моему опыту, все зависит от конечного продукта, от его качества, от того, что дизайнеру необходимо передать (в том числе и с помощью шрифта).
Для дизайнера шрифт - это не просто обезличенные символы, это нечто намного большее. Это способ общения с человеком, это качество общения, качество сервиса, эмоции, способ восприятия информации, нарратива. Это целая вселенная.
Сам по себе шрифт - это мощнейший инструмент, который нужно уметь использовать. Подобрав неверный шрифт, можно не то чтобы испортить атмосферу игры, можно просто сделать игру бессмысленной, непонятной, противоречивой.
Давайте рассмотрим следующий пример.
Допустим, у нас игра для детей 7-10 лет, без насилия. В игре есть милые NPC, которые здороваются с вами, сажают овощи, желают хорошего дня, вечера и так далее. Что-то типа игры про весёлую ферму.
И, допустим, в этой игре дизайнер принял решение писать пожелания и все остальные фразы милого зайки-NPC красным цветом и таким шрифтом потому, что шрифт бесплатный и не было времени работать над собственным шрифтом:
Вы прочувствовали всю доброту пожеланий?
Или вот ещё варианты передачи фраз добродушного зайчика посредством шрифта:
Наверно очевидно, что шрифт решает многое и он, часто, крайне важен.
Одна и та же фраза может передавать абсолютно разную информацию. И эта информация заложена в контексте, в данном случае в шрифте.
Пример с зайчиком, конечно, утрирован, но он хорошо показывает мощь и возможности передачи огромной информации с помощью такого, на первый взгляд, незаметного инструмента как шрифт.
Бесплатные шрифты
Согласно моему опыту, у бесплатных шрифтов есть большие недостатки. Во-пепвых бесплатных шрифтов очень много (тысячи). Во-вторых лично мне не удалось найти в этой разнообразной тьме что-то подходящее для нашего проекта. Убив значительное время на поиски, я изрядно замучался и был поражён скудностью огромного разнообразия в бесплатном.
Среди платных шрифтов мне попалась пара подходящих вариантов. Но в этих вариантах отсутствовали либо кириллические символы, либо латинские. Цена использования каждого из таких шрифтов в коммерческих проектах (приложения) была в диапазоне по 90 - 120 тыс. руб за шрифт. Для использования на сайте цена была ниже. Ну а для личного приватного использования плата вовсе не взымалась.
Перед разработчиками стоит непростая проблема:
- либо нужно вложить 2x * много денежных средств на приобретение шрифта
- либо нужно вложить много сил и создать свой шрифт
Для нас выбор был очевиден - придётся работать и создавать свой шрифт.
Создание векторного шрифта
Начну сразу с платного ПО, которое использовал. Birdfont - замечательная программа за $5 на которой мы остановили свой выбор. Программа позволила быстро перенести растровый шрифт в векторный формат.
Достоинства:
- очень дешёвая лицензия
- достаточно удобная (когда освоишься)
Недостатки:
- тормозит, есть баги, недоработки
- интуитивно непонятный интерфейс и горячие клавиши
Возможно есть ещё какие-то недостатки, которые видны профессионалам, но меня пока все устроило (особенно цена).
Тонкости создания глифов
Birdfont сильно упростил процесс создания векторных глифов и мы расширили поддержку алфавита. Добавили поддержку следующих языков (кроме английского и русского):
- немецкий
- французский
- испанский
- итальянский
- польский
- чешский
- венгерский
Кажется ничего не упустил.
В процессе работы над глифами обнаружил, что играл со шрифтами и сильно проиграл.
Ситилизация шрифтов - головная боль для дизайнера. Как можно играть с дизайном глифов и проиграть.
Дело в том, что мы пытались стилизовать шрифты других стран без глубокого понимания того, что можно делать, а что нельзя: упрощали, перерисовывали части глифов на свое усмотрение. Ниже представлены примеры глифов, которые ранее стилизовали неверно:
В конце мы передали свой шрифт друзьям-лингвистам из бюро переводов Code-Switcher, чтобы похвастаться они все проверили. У них, в основном, трудятся переводчики-носители языка, они-то точно должны адекватно оценить нашу работу. Те, в свою очередь, посмотрели и отправили в ответ пренеприятное известие примерно такого содержания:
Ваши символы "A", "B", "C" стилизованы не совсем верно. Символы "D", "E", "F" содержат серьёзные проблемы.Далее следовало уточнение о том, что неверно и почему. В целом наш шрифт вызывал бы неприязнь, отторжение у носителей языка. Забраковали работу :(
Особо отмечу, что сильно забраковали эти два символа, которые похожи на "А" и "С". Вот они:
Заметили мелкие крючки на конце?
Крючки, точки, кружки с отверстием, вопросительный знак перевернутый вверх ногами - неучтенные мною глифы, которые оказались серьёзной болью при дальнейшем расширении языковой поддержки. Ребята из кодсвичера доходчиво объяснили, что наши дизайнеры слабо разбираются в шрифтах и нам необходимо ввести дополнительные символы вопроса и восклицания для испанского языка.
Дело в том, что испанцы сперва ставят перевернутый знак вопроса / восклицания, далее идёт предложение, а в конце ставятся обычные знаки вопроса / восклицания. И без перевернутых знаков в начале предложения никак не обойтись, просто вот совсем никак, вынь да положь.
В итоге мы учли всю критику от ребят из бюро переводов и добавили полную поддержку перечисленных выше языков.
Теперь попробуем сравнить текст на немецком и английском (наш шрифт) и текст на русском (точно не помню какой именно шрифт в примере):
Наверно заметили, что здесь что-то не то с кириллическим русским текстом. Да, это так. Разный шрифт - разный дизайн.
Кажется, что текст выделяется из-за того, что шрифт очень широкий. И все можно исправить простым сжатие глифов. На самом деле проблем больше и простым ужатием шрифта по горизонтали не обойтись.
Штош, что только не сделаешь, чтобы конечный продукт выглядел неразношорстно, в одном стиле. Наш финальный результат:
Подключение шрифтов на сайт
Пример #1 — Подключаем шрифт PT Sans через Google Fonts
- Заходим на сайт fonts.google.com и находим шрифт PT Sans;
- Нажимаем кнопку Select this font;
- Нажимаем на Family Selected;
- Во вкладке Customized выбираем начертания и Cyrillic;
- Копируем строку с подключением шрифта во вкладках EMBED → @IMPORT.
Вставляем строку с подключением в начало CSS файла:
@IMPORT url('https://fonts.googleapis.com/css?family=PT%20Sans%3A400i%2C7...);
Копируем свойство font-family:
Пример #2 — Подключаем шрифты PT Sans и PT Serif в Drupal 8 через файл темы .libraries.yml
Аналогично примеру #1 получаем URL подключения шрифтов из строки @import:
fonts.googleapis.com/css?family=PT%20Sans%3A400%2C400...
В файле темы .libraries.yml подключаем шрифты по образцу:
fonts.googleapis.com/css?family=PT%20Sans%3A400%2C400...,
Сохраняем и сбрасываем кэш.
Пример #3 — Подключаем шрифт PT Sans локально
- Заходим на сайт Google Webfonts Helper;
- В поиске находим шрифт PT Sans;
- Выбираем начертания и Cyrillic;
- Пролистываем вниз и пишем где будут находится шрифты относительно .css файла;
- Копируем CSS код и вставляем его в .css файл;
- Скачиваем архив с шрифтами, разархивируем его и размещаем шрифты в нужном месте.
Вот так выглядит скопированный CSS:
/* pt-sans-regular - cyrillic_latin */
@font-face {
font-family: 'PT Sans';
font-style: normal;
font-weight: 400;
src: url('../fonts/pt-sans/pt-sans-v9-cyrillic_latin-regular.eot'); /* IE9 Compat Modes */
src: local('PT Sans'), local('PTSans-Regular'),
url('../fonts/pt-sans/pt-sans-v9-cyrillic_latin-regular.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */
url('../fonts/pt-sans/pt-sans-v9-cyrillic_latin-regular.woff2') format('woff2'), /* Super Modern Browsers */
url('../fonts/pt-sans/pt-sans-v9-cyrillic_latin-regular.woff') format('woff'), /* Modern Browsers */
url('../fonts/pt-sans/pt-sans-v9-cyrillic_latin-regular.ttf') format('truetype'), /* Safari, Android, iOS */
url('../fonts/pt-sans/pt-sans-v9-cyrillic_latin-regular.svg#PTSans') format('svg'); /* Legacy iOS */
}
/* pt-sans-italic - cyrillic_latin */
@font-face {
font-family: 'PT Sans';
font-style: italic;
font-weight: 400;
src: url('../fonts/pt-sans/pt-sans-v9-cyrillic_latin-italic.eot'); /* IE9 Compat Modes */
src: local('PT Sans Italic'), local('PTSans-Italic'),
url('../fonts/pt-sans/pt-sans-v9-cyrillic_latin-italic.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */
url('../fonts/pt-sans/pt-sans-v9-cyrillic_latin-italic.woff2') format('woff2'), /* Super Modern Browsers */
url('../fonts/pt-sans/pt-sans-v9-cyrillic_latin-italic.woff') format('woff'), /* Modern Browsers */
url('../fonts/pt-sans/pt-sans-v9-cyrillic_latin-italic.ttf') format('truetype'), /* Safari, Android, iOS */
url('../fonts/pt-sans/pt-sans-v9-cyrillic_latin-italic.svg#PTSans') format('svg'); /* Legacy iOS */
}
/* pt-sans-700 - cyrillic_latin */
@font-face {
font-family: 'PT Sans';
font-style: normal;
font-weight: 700;
src: url('../fonts/pt-sans/pt-sans-v9-cyrillic_latin-700.eot'); /* IE9 Compat Modes */
src: local('PT Sans Bold'), local('PTSans-Bold'),
url('../fonts/pt-sans/pt-sans-v9-cyrillic_latin-700.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */
url('../fonts/pt-sans/pt-sans-v9-cyrillic_latin-700.woff2') format('woff2'), /* Super Modern Browsers */
url('../fonts/pt-sans/pt-sans-v9-cyrillic_latin-700.woff') format('woff'), /* Modern Browsers */
url('../fonts/pt-sans/pt-sans-v9-cyrillic_latin-700.ttf') format('truetype'), /* Safari, Android, iOS */
url('../fonts/pt-sans/pt-sans-v9-cyrillic_latin-700.svg#PTSans') format('svg'); /* Legacy iOS */
}
/* pt-sans-700italic - cyrillic_latin */
@font-face {
font-family: 'PT Sans';
font-style: italic;
font-weight: 700;
src: url('../fonts/pt-sans/pt-sans-v9-cyrillic_latin-700italic.eot'); /* IE9 Compat Modes */
src: local('PT Sans Bold Italic'), local('PTSans-BoldItalic'),
url('../fonts/pt-sans/pt-sans-v9-cyrillic_latin-700italic.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */
url('../fonts/pt-sans/pt-sans-v9-cyrillic_latin-700italic.woff2') format('woff2'), /* Super Modern Browsers */
url('../fonts/pt-sans/pt-sans-v9-cyrillic_latin-700italic.woff') format('woff'), /* Modern Browsers */
url('../fonts/pt-sans/pt-sans-v9-cyrillic_latin-700italic.ttf') format('truetype'), /* Safari, Android, iOS */
url('../fonts/pt-sans/pt-sans-v9-cyrillic_latin-700italic.svg#PTSans') format('svg'); /* Legacy iOS */
}
А так список файлов с шрифтами:
Команда ls в терминале
Если все сделано правильно, то шрифты будут подключены локально.
Энциклопедия символов «Юникодия» v1.1: я это сделал!
Напоминаю: я пишу программу под Windows — энциклопедию символов и замену стандартной Таблице символов. Качать тут.
Я дошёл уже до версии 1.1, и вот что вышло. Пишу крупные изменения и 1.0, и 1.1.
Поддержка ВСЕГО Юникода 14
Вы правильно прочитали, не осталось ни одного тофу. Под Windows 10/11, разумеется — пользователям 7-ки больших обещаний не делаю. На картинке сверху — моя интерпретация кипро-минойской письменности, добавленной этой осенью. Да, сам рисовал шрифт, и вот откуда эта интерпретация взялась.
1. Реальный памятник, найденный где-то на Турецком Кипре.
2. Его факсимиле.
3. Прорисовка Майкла Эверсона (2020).
Египетские и анатолийские иероглифы
Вообще-то в коллекции Noto для них есть отличные шрифты. Анатолийские выше всяких похвал, а у египетских один недостаток: как отрендерить в маленькую клеточку Юникодии? Ларчик просто открывался: OTF, который я кое за какие технические подробности недолюбливал. Но тут сильно другой рендерер конкретно для этого шрифта сработал на все 146%.
Впоследствии выяснилась запара: символы счётных палочек иногда «проваливаются между пикселей». Нарисованы девять палочек, а видны только три! Их я просто скопировал в свой резервный TTF и прохинтовал, но тут случилось забавное: под Windows 7 я никак не мог прописать в заголовках резервного шрифта, что иероглифы поддерживаются. Я на подобный глючок натыкался и раньше, и под Windows 10 тоже — решилось просто, в Qt есть стандартный обход QRawFont.
А анатолийские — просто за компашку получили OTF-шрифт. Попробовал также заменить OTF’ом пахау хмонг, чей рендеринг мне тоже не нравился — не получилось.
Китайский, корейский, японский
ККЯ-символов всего 115 тысяч, или 79% всего Юникода. Из них 94 тысячи иероглифов, остальное — корейский, тангутский, спецсимволы, японский, киданьский, нюй-шу, примерно в таком порядке. И где достать шрифты, которые поддержат такую громадину?
Оказалось, есть сайт GlyphWiki, оперативно реагирующий на изменения в Юникоде, но тамошние SVG — а значит, все шрифты, сделанные из них — технически страшны. И есть типограф Эндрю Уэст, который потихоньку клепает шрифт Babelstone Han. Собственно, задача — собрать из того и другого подходящую коллекцию. Шрифт с GlyphWiki я заменил другим, и целую ночь торчал в FontForge, исправляя хоть самые страшные глюки. Заодно ушло 10 мегабайт архива. Но это значит, что для пользователей Windows 7 ушли несколько древних письменностей, в частности готский — были за компашку в одном шрифте и исчезли в другом. Простите уж, я и не обещал пользователям 7-ки полную поддержку всего.
Декапитализация
К сожалению, в стандартах Юникода символы называются большими буквами: CANADIAN SYLLABICS WOODS-CREE FINAL TH. Но у меня с самого начала всё няшно и цивильно, и за это отвечает декапитализация — система из 700 правил и 250 исключений. Это немало, но строк-то в Юникоде 45 тысяч — даже такая недоавтоматика лучше ручной работы.
«Canadian» — название письменности, сделать с большой буквы и включить следующий механизм.
«syllabics» — ключевое слово. Оставить с маленькой, но после сделать большую букву.
«Woods-Cree» и «final» — прилагательные. Если есть большая буква, она проталкивается по прилагательным дальше до Th. Так что получилось бы «Woods-cree final Th», но лесные кри — индейское племя и в английском с больших букв.
Уже четыре правила.
Не буду всё перечислять, но новых правил декапитализации я добавил очень много. Самое чувствительное — отыскал и отметил альтернативные написания имени Аллах. А также вручную перебрал все названия с «ligature» — никакая автоматика не расставит правильно большие буквы в каком-нибудь «Hebrew ligature Yiddish Yod Yod Patah».
Поиск
Уже следующей осенью моя программа устареет — появится Юникод 15, в котором будут веер, афро-гребень и WiFi. К тому же некоторые программы (и моя Юникодия тоже!) вовсю пользуются личными символами. Так что поиск по несуществующим символам стал более подробным. Вот, например, что увидим, когда поищем «590».
При том, что ближайший символ к 590 — это U+0591, какой-то еврейский умляут, я не стал его выводить, а коряво воспроизвёл иконку.
Видим ещё одну фишку — поиск не только по шестнадцатеричному коду, но и по десятичному. Нашло не только U+0590, но и 590₁₀=24E. Поиск по названиям существовал и ранее, причём достаточно адекватный.
Собственные изображения спецсимволов
Некоторым символам — форматирующим или с особой функциональностью — в общем, забранным в пунктир — приходится делать своё изображение. Эти изображения хранятся в моём резервном шрифте в пользовательских позициях (E001 и далее), налажен механизм отрисовки. Вот несколько штук.
Постарался проверить всё. Например, индийские письменности слоговые — как в каждой из них работает запись сложных слогов? Условный «стол» даже в родственных письменностях может писаться совершенно по-разному.
• са⸜ то ла⸜ (то, что я обозначил чертой, называется «вирама» или «халанта» и стирает букву «а» из слога) — исходная письменность брахми, а также некоторые малоразвитые письменности Юго-Восточной Азии
• сᵊ то лᵊ — гласная по умолчанию «а» стала немой или почти немой — пенджабский с письменностью гурмукхи
• сᵀо ла⸜ — во втором слоге знакомая нам вирама, а в первом «с» и «т» склеились в лигатуру — так работает хинди с письменностью деванагари
• с то л — лаосский в XX веке отказался от гласной по умолчанию
А правда ли, что юникодными знаками европейских нот можно записать «Кузнечика»? Оказалось, нет. Даже несмотря на то, что играется на одной гитарной струне.
В левосторонних письменностях кхароштхи и ханифи перед текстами-образцами для правильного рендеринга добавил знак RLM.
Теперь слог «дхик» закодирован именно так, как в описании, только перед ним RLM = right-to-left mark. Копируй, вставляй, разбирай на символы — всё честно, как и подобает энциклопедии Юникода. (Раньше было ка+вирама+дха+и — и неловкое объяснение: простите, по-другому не рендерит.)
Недоработал: когда писалась статья, уже нашёл пару незначительных ошибок в описаниях. Ничего критичного, исправлю в следующей версии. (А ещё в версии 1.1 допустил неудачный рендеринг десятка латинских умляутов — это уже критично, быстренько перевыпустил.)
Так что спасибо за внимание!



































