原因: WebGL无权限读取本地操作系统的字体文件
方案: 多语言,字体文件打bundle, 把字体文件打进包再发布
中文字体不能用Unity原生字体,需要自己导入字体
我们选一个编码不太全的字体为例
用FontCreator工具打开字体,发现,这个字体只有英文和一些符号已经一些不认识的字母,没有中文
我们就选择这个字体,输入中文,看看会出现什么效果
上图用我们精简的没有中文的字体,下图用默认字体,最终效果如下
Whaaat? 两个字体英文不同,但是中文完全一样,这下应该明白了,使用动态字体,如果所输入的文字在字体中找不到相应的编码,就会自动从系统默认字体中找到该字体!Windows下unity自带字体为Arial,在程序运行过程中如果遇到字库中没有的字,程序就会从系统的默认字体库中查找对应的文字,如果系统默认的字库中也没有这个字,那么就会造成字体不显示问题。
为了进一步验证,我们把这个字体改成非动态字体再看看
改成非动态字体以后,显示的已经是乱码了。
参考:
关于Unity中的字体常用的有:内置字体,外部导入的字体,自定义的字体。
1,内置字体。
内置字体一般是指unity自带的字体,Windows下unity自带字体为Arial,如果游戏中使用Arial字体,在某些机型上可能显示不全。原因是Arial是英文字体,并不包含中文字体。在Unity中如果使用了默认的Arial字体,在程序运行过程中如果遇到字库中没有的字,程序就会从系统的默认字体库中查找对应的文字,如果系统默认的字库中也没有这个字,那么就会造成字体不显示问题。在Android系统中Unity默认会去查找名为DroidSansFallback的字体,这个字体是android的默认字体,但是因为android系统的可定制性,太过自由,很多手机厂商会去修改默认字体。在android系统是根据字体的文件名称来找字体的,但unity识别字体却是通过字体内部的设置来识别字体的,所以说,即使在anroid手机中有DroidSansFallback.ttf字体,也有可能unity找不到这个字体。由于上面的原因,尽量不要使用unity的默认字体Arial,除非你做的游戏是纯英文的。
2.动态字体
如果你有一个.ttf的字体文件,想要在unity中使用此字体,可以直接把此文件拖到unity内,如:
其中,Font size字体大小,一般设置为16,数值越大,设置文字时字体对应的texture越大,所以这个值不应设置过大.
Font Names默认导入的一个字体,这个参数的主要作用实际上是设置替代字体用的,当程序需要某一个字体时,首先会从当前字体查找字符,如果没有,会依次查找FontNames列表里的其它字体,直到找到或者找完为止。
Incl.FontData选项打上勾,在导出包的时候把字体添加到包中,若不打勾,则不会将该字体打包,程序运行时会从FontNames列表里检索需要的字体,如果没有,字体就不显示。
如果游戏中一直都在使用A字体,突然要改为B字体,可以在A字体的FontNames里填入B字体名字,A字体的Incl.FontData不打勾,B字体的Incl.FontData打勾。
Character选项
大多数时候我们都是选择Dynamic,另外Custom set有时也会用到,比如选择了Custom set
并且Custom Chars设置为ABC,那么使用此字体的文本只能显示ABC这三个字符,其它字符不能显示。
动态字体字体丢失问题的解决办法:
1,我们用的TTF动态字体,Text每次赋值的时候Unity会生成贴图,以及保存UV信息,显示字体时根据UV信息去生成的贴图里取出渲染到屏幕上。出现花屏可能是贴图更新了,但UV信息没有更新,所以就取不到,这时需要重新用新的UV去取。
bool isDirty = false;
Font dirtyFont = null;
void Awake()
{
Font.textureRebuilt += delegate(Font font1)
{
isDirty = true;
dirtyFont = font1;
};
}
void LateUpdate()
{
if (isDirty)
{
isDirty = false;
foreach (Text text in GameObject.FindObjectsOfType<Text>())
{
if (text.font == dirtyFont)
{
text.FontTextureChanged();
}
}
dirtyFont = null;
}
}
2.TTF字体的文件下,会生成一个texture文件及material文件。当需要显示文字的时候,会通过RequestCharactersInTexture函数向Font请求更新文字信息,然后使用GetCharacterInfo获取文字信息来渲染。在调用GetCharacterInfo的时候要保证文字都通过RequestCharactersInTexture请求过了。如果请求的时候,Font内部维护的texture不够用了,就会触发textureRebuildCallback的回调,通知外部Font的对象,其内部的texture被更新了,外部应该重新刷新。
Unity的Font默认的texture大小是256X256,在纯英文的情况下,是完全够用的。但是汉字,日文等字体就完全不够了。如果unity的刷新回调触发,则要重新刷新所有的文本控件。这样就容易出现字体破碎的情况。因为一般情况下我们请求的文字不会很多,使用的texture不会超过256x256,unity不会自动扩展texture大小。但我们请求的文字过多时,texture如果不够了,这时就需要在回调函数中刷新字体,如果我们连续请求文字,每次texture都需要扩展(需要回调刷新),于是就会出现不停刷新,字体也可能会破碎。
解决办法:可以游戏刚开始时请求足够多的文字,那么unity就会内部自动扩展font的texture大小,于是就可以避免不停刷新的情况。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class FontTextureSize : MonoBehaviour {
// Use this for initialization
void Start () {
Font stx = Resources.Load<Font>("STXINWEI");
Texture tex = stx.material.mainTexture;
Debug.Log(string.Format("texture:{0} {1}", tex.width, tex.height));
TextAsset ta = Resources.Load<TextAsset>("word");
string word = ta.text;
stx.RequestCharactersInTexture(word);
tex = stx.material.mainTexture;
Debug.Log(string.Format("texture:{0} {1}", tex.width, tex.height));
}
// Update is called once per frame
void Update () {
}
}
3.自定义的字体