Введение
Всем привет! Меня зовут Александр и я Unity Developer более 7 лет. В этой статье мы попробуем решить проблему шрифтов раз и навсегда (в мобильных играх так точно). Способ для Unity не самый очевидный, про него не так много написано и все ответы приходилось собирать по кусочкам, собственно поэтому и решил написать статью. Сразу перейдем к техническому заданию.
Нужно сделать локализацию для мобильной игры, с такими требованиями:
-
Шрифты не должны занимать много места в билде, желательно до 10 мб максимум
-
Шрифты должны быть сгенерированы без лишних заморочек для Text Mesh Pro
-
Шрифты должны поддерживать такие языки: English, Russian, Ukrainian, German, French, Spanish, German, Italian, Portuguese, Arabic, Japanese, Chinese, Korean, Hindi
Проблема
Итак, давайте разбираться в самой задаче по порядку. Первый пункт про размер шрифта: если подбирать шрифт для европейских языков, то такой шрифт будет весить обычно не больше 1 мб. Но чем ближе мы будем двигаться в сторону Азии, тем больше будет размер шрифта (интересное сходство🤔). В итоге получается примерно 24.6 мегабайт, что не мало для мобильной игры. Стоит учесть, что некоторые шрифты взяты в единственном стиле, иначе размер увеличивается практически вдвое.
Language |
Font |
Size |
English, Russian, Ukrainian, German, French, Spanish, German, Italian, Portuguese |
Noto Sans |
0.6 MB |
Arabic |
Noto Sans Arabic |
0.7 MB |
Hindi |
Noto Sans Devanagari |
0.9 MB |
Japanese |
Noto Sans Japanese Black |
5.7 MB |
Korean |
Noto Sans Korean Black |
6.2 MB |
Chinese |
Noto Sans Chinese Simplified |
10.5 MB |
|
Итого: |
24.6 MB |
Второй пункт так же не простой из-за не знания всех языков, при генерации TMP шрифта можно упустить какие-то символы. Например для китайского языка есть 3500 часто используемых иероглифов из 20000 только официального словаря. С третьим чуть полегче, нам помогут дизайнеры найти нужные шрифты, и наше дело их добавить в игру.
Решение проблемы
После долгого поиска шрифтов и осознания, что они будут занимать 1/3 размера игры, появилась идея: “В операционных системах же есть уже встроенные шрифты для разных языков, почему бы их не использовать”. Потратив некоторое время на поиски, я наткнулся на форум, где уже этот вопрос обсуждался с разработчиком TMP. В треде добились чтобы разработчик сделал такой функционал. Хоть функционал есть, но шрифты, о которых пишет Apple и Google, находятся не все или названы совсем не так. Тут можно найти списки шрифтов для мобильных платформ
Допустим, мы нашли нужные нам шрифты, теперь давайте их подключим. Нам понадобиться какой-то основной шрифт, скорее всего это будет шрифт Английского язык, его мы заранее создадим в нашем проекте (туториал). Дальше загрузим нужные нам шрифты из ОС:
private static IEnumerable<(NativeFontData data, string path)> GetNativeFonts(IEnumerable<NativeFontData> data) { var nativeFonts = Font.GetPathsToOSFonts(); foreach (var fontData in data) { var currentFontName = fontData.Name; var nativeFont = nativeFonts.FirstOrDefault(nf => IsTargetFont(currentFontName, nf)); if (nativeFont is not null) { yield return (fontData, nativeFont); } else { Debug.Log($"Can't find any font with name: {fontData.Name}"); } } yield break; bool IsTargetFont(string target, string current) { return target == Path.GetFileNameWithoutExtension(current); } }
Теперь нам нужно эти шрифты конвертировать в TMP и настроить. При настройке шрифта нужен индивидуальный подход для каждого, так как Японский шрифт с теми же настройками как у Итальянского может хуже читаться или занимать больше места в памяти.
private static IEnumerable<TMP_FontAsset> ConvertNativeFontsToTmp(IEnumerable<(NativeFontData data, string fontPath)> fontPaths) { foreach (var (data, fontPath) in fontPaths) { var font = new Font(fontPath); var tmpFontAsset = TMP_FontAsset.CreateFontAsset(font, data.PointSize, data.Padding, GlyphRenderMode.SDFAA_HINTED, data.AtlasSize.x, data.AtlasSize.y); yield return tmpFontAsset; } }
Чуть подробнее опишу некоторые конфигурации у шрифта:
-
Point Size — качество рендеринга символа, выше лучше (хороший показатель 40-50)
-
Padding — расстояние между символами в атласе
-
Atlas Size — размер каждого создаваемого атлас
-
Dynamic Font — каждый символ, перед отображением, будет пытаться найти такой же в шрифте и после добавит в атлас
-
Multi Atlas Textures — если заканчивается место для символов создастся новый атлас, иначе не будет добавлен символ
Полный код можно найти здесь. Как видно из кода, в функции есть аргумент текущего языка платформы, в моем случае мы используем только 1 язык без возможности изменения его во время игры. В случае, когда понадобятся все поддерживаемые языки (например для чатов), необходимо немного усовершенствовать функцию. Здесь стоит быть осторожным: память на устройстве не резиновая, и стоит контролировать количество и размеры атласов шрифтов (опять же отсылка к Китайскому языку). Так же я добавил пример настроек для разных платформ, которыми сам пользуюсь.
var fontData = Application.platform switch { RuntimePlatform.Android => new[] { //Android new NativeFontData("NotoNaskhArabic-Regular"), //Arabic new NativeFontData("NotoSansDevanagari-Regular"), //Hindi new NativeFontData("NotoSansCJK-Regular", 40, 3, new Vector2Int(2048, 2048)), //Chinese, Japanese, Korean new NativeFontData("Roboto-Black"), //Unicode new NativeFontData("Arial"), new NativeFontData("LiberationSans") }, RuntimePlatform.IPhonePlayer => new[] { //iOS new NativeFontData("HiraginoMincho"), //Japanese new NativeFontData("NotoNastaliq"), //Arabic new NativeFontData("DevanagariSangamMN"), //Hindi new NativeFontData("PingFang", 40, 3, new Vector2Int(2048, 2048)), //Chinese new NativeFontData("AppleSDGothicNeo"), //Korean new NativeFontData("SFUI"), //Currency symbols new NativeFontData("Arial"), new NativeFontData("LiberationSans") }, _ => new[] {new NativeFontData("Arial"), new NativeFontData("LiberationSans")} };
Заключение
В финальном результате получилось оптимизировать билд, процессы поиска и добавления шрифтов. Вот небольшой список достижений:
-
В проекте только один шрифт
-
Уменьшился размер всех шрифтов до 500 кб
-
Теперь нет необходимости конвертации шрифта в TMP
-
Поддержка практически любых языков
P.S. Еще раз продублирую ссылку на репозиторий. Если понадобится сделать из этого пакет — напишите об этом в комментах.
ссылка на оригинал статьи https://habr.com/ru/articles/828620/
Добавить комментарий