开题
众所周知,大部分游戏在打包的时候,会把字体里面明显用不到的字符集删去(比如说中文),也可能用的字体压根就没有中文字符集,所以在做汉化的时候,经常碰到中文显示XXXX
的情况。
而出于对还原度的考虑,我对于汉化的字体有以下几点考量:
- 样式尽量与原字体一致,如是否衬线、笔画粗细、字符宽高比、运笔风格等
- 对于原字体有的字符集,尽量从原字体中迁移,而不是全部采用新字体
- 全半角标点除字宽外尽量一致,所以全角标点最好从原字体的半角标点中迁移,并保留中文字宽
- 原字体尽量找未精简版本,因为游戏内打包的大概率是精简版的
- 原字体可能有自定义字符区,可能会在游戏内使用,所以也得迁移过来
所以,FontCreater
无疑是字体合并的神器了。
本篇博客以游戏《史丹利的寓言:终极豪华版》(The Stanley Parable: Ultra Deluxe)
为例,记录了Unity
游戏汉化过程中从缝合字体到打包SDF
的完整经过。
开始捞字体
首先找到一个和原字体风格尽量一致的中文字体,因为游戏中使用的字体比较多,这里以比较有特色的字体LeagueGothic-Regular
为例。
先是大海捞针找到一个符合要求的中文字体,这里选择了方正俊仪体-Bold
,至于为啥要Bold
版本呢?因为这个版本的笔刷粗细正好和原字体非常接近。
开始缝合
先去Google Fonts
下载原字体的未精简版本,也就是官方原版,然后用FontCreater
打开Google版和中文版两个字体。
将两个字体都按Unicode 字码点
排序,方便后续比对。
两边基本拉丁字母
区都是95/95
满的,那就直接从原字体全选复制过来。
中文字体这边拉丁字母补充-1
没满,但是谷歌版这边是满的,那就直接复合一下中文字体的这个字符区(复合完了记得再次排序,因为复合是添加到本区的尾部,但是已有的字符和新添加的可能顺序是交叉的)。
Google版的还有俩非标准字符,不确定游戏版的字体有没有,先别管。
也是从原字体复制过来就完成了这个字符区。
再看拉丁字母扩展-A
区的,两边都没满,不过原字体超过半数了,那就两边都复合一下再排个序,然后全选复制过来,再把空的删掉就行。
拉丁字母扩展-B
区的两边都没咋满,所以直接记一下原字体的字符分布然后在新字体这边添加就行(当然添加完还是记得排序)。
不过新字体多了个ngrave
字符,原字体里没有,直接删掉,然后其他的字符也复制过来就行。
然后新字体还有个国际音标扩展
区,这个反正不是中文里用的,删掉就完事。
剩下的几个区也和上面逻辑一样,该补的补,该替换的替换,该删的删。
最后剩下全角与半角的迁移,方法是先从原字体复制,然后在粘贴的时候选择特殊粘贴,只保留轮廓,就可以保留新字体的全角字宽(可以多选复制和粘贴)。
当然,这样子复制过来的字形,默认是居左的,所以咱们需要让其居中(感觉大部分全角标点都是居中吧),不过这一步留到最后做,不然现在居中了待会从游戏版迁移完后还得重新搞。
咱们现在已经完成了从谷歌版到中文字体的迁移,然后再从游戏版字体往中文字体迁移一次,因为游戏版可能对字形有改动,这里不多说了,方法和上面一样,主要就是覆盖字形。
值得注意的是游戏版字体有一些非标准字符,最好也复制过来,方法是点添加字符看哪个非标准是绿的,就在新字体那边添加上。
然后回来去全角区搞居中,双击字形,Ctrl+A
全选轮廓,Shift+→
几次把定位点大致对准中线(这边中线是500
),然后Ctrl+滚轮
放大到究极大,→
几次再次大致对准中线,最后Ctrl+→
彻底对准。
最后将新字体的字体属性全部按游戏版字体的字体属性填写即可。
最后的最后,可以尝试导出字体。
发现中文字符间距有点大,于是用自动度量
去改改。
改之前先记一下哪些字符区是全角并且需要改间距的。
为了所有中文字符统一间距,咱们这边选固定字宽
。
选择刚才记下的那些区域后,Finish
即可。(不太好选)
最终效果如下:
开始打包
打开Unity
,创建一个空项目,打开Package Manager
。
添加Asset Bundle Browser
和TextMeshPro
把字体文件拉到Assets
区。
用TextMeshPro
的Font Asset Creator
创建SDF
字体文件。
项目首次使用这个功能会弹出Import
,把两个都导入就行。
如下两个按钮都灰了就导入完了,直接关掉。
看一下字符集的范围设定选项,有这么多可以选。
一般是Unicode Range (Hex)
就够用,但是这玩意的文本框有最大长度现在,如果精细到每个字符的话,其实是不太够的...所以咱选择Characters from File
,然后去写代码打个字符集出来。
from fontTools.ttLib import TTFont
def main():
otf = TTFont("font/LeagueGothic-Regular/LeagueGothicWithFZJunYT-B-Regular.otf")
keys = otf.getBestCmap().keys()
with open("font/LeagueGothic-Regular/set.txt", 'w', encoding="UTF-8") as f:
for i in keys:
f.write(chr(i))
if __name__ == '__main__':
main()
把字符集文件拖到Assets
里。
然后选择这个文件。
其他配置选项的话,测试的时候,Packing Method
建议用Fast
,最终打包时用Optimum
;Samping Point Size
和Atlas Resolution
根据字符集数量调整,参数越大打出来的包越大,但是清晰度也越高,不过前者过大或者后者过小会造成一张图里塞不下所有字符集,所以需要多测试几次找到最合适的参数。
比如说咱们这回就没打成功,字符集数量太多了,只塞下5k+
就放不下了,所以需要改改参数。
最终在字体大小是94
的时候刚好塞下,把打出来的字体包先Save
一下去游戏里看看实际情况,如果效果比较好的话就可以打Optimum
版本的了。
开始ab打包,打开AssetBundle Browser
。
先把字体源文件拖进来(顺序不要搞错)。
再把SDF
文件拖到右侧,使两者在同一个包内。
切到Build
选项卡,参数按自己需求改改就可以Build
了。
最终得到:
替换到游戏里去看看(怎么替换不是本篇博客要讲的内容,不做讨论),感觉效果挺好的。
所以最后就是去打包个Optimum
版本就大功告成了(巨慢)。