Unity动态字体在手机上出现字体丢失问题解决

      在我们游戏的开发过程中,在部分手机上运行游戏的时候,出现了字体丢失的问题,出问题的手机似乎用的都是高通芯片。

      使用的unity是4.2.0版本,ngui是3.4.9版本。

      在unity的论坛及unity answer中寻找问题的原因及解决办法许久未果,后来在csdn里偶然找到一篇博文,里面讲到的问题出现的原因以及相应的解决办法。根据文中的办法,我试验后证实的确可以解决问题。

      博文地址:http://blog.csdn.net/langresser_king/article/details/22095235

      在unity editor中可以看到,使用的字体ttf文件下,会生成一个texture文件及material文件。当需要显示文字的时候,会通过RequestCharactersInTexture函数向Font请求更新文字信息,然后使用GetCharacterInfo获取文字信息来渲 染。在调用GetCharacterInfo的时候要保证所有文字都通过RequestCharactersInTexture请求过了。

      如果请求的时候,Font内部维护的texture不够用了,就会触发textureRebuildCallback的回调,通知外部使用Font的对象,其内部的texture被更新了,外部应该重新刷新。

      原文中提到,是因为texture的大小没有被及时扩大而导致字体丢失。但是在我多次测试之后,猜测问题的原因应该不是这一点。因为在PC上或者其他手机上并不会出现字体丢失的问题,问题并不是出现在unity动态字体的策略上。但是这个问题是可以通过在最开始的时候使用方法将texture尺寸扩大的做法来规避掉。真正的原因实在未能找出。

      下面提供规避掉这个问题的做法,供参考:

private void FixBrokenWord()
    {
        if (chineseText == null)
        {
            var wordFileRes = ResMngr.GetInstance().LoadSync("ui", "UI/font/chineseWords");
            if (wordFileRes != null)
            {
                TextAsset worldFile = wordFileRes.GetObject() as TextAsset;
                chineseText = worldFile.text;
                Debug.Log(string.Format("chinese font size: {0}", chineseText.Length));
            }
        }
        var fontRes = ResMngr.GetInstance().LoadSync("ui", "UI/font/font_FZCYJW_28");
        if (fontRes != null)
        {
            GameObject fontPrefab = fontRes.GetObject() as GameObject;
            baseFont = fontPrefab.GetComponent<UIFont>().dynamicFont;
        }
        if (baseFont != null)
        {
            baseFont.RequestCharactersInTexture(chineseText, 28);
            Texture texture = baseFont.material.mainTexture;
            Debug.Log(string.Format("Texture size: {0}, {1}", texture.width, texture.height));
        }
        fontRes = ResMngr.GetInstance().LoadSync("ui", "UI/font/font_STXINGKA_54");
        if (fontRes != null)
        {
            GameObject fontPrefab = fontRes.GetObject() as GameObject;
            baseFont = fontPrefab.GetComponent<UIFont>().dynamicFont;
        }
        if (baseFont != null)
        {
            baseFont.RequestCharactersInTexture(chineseText, 54);
            Texture texture = baseFont.material.mainTexture;
            Debug.Log(string.Format("Texture size: {0}, {1}", texture.width, texture.height));
        }
    }

这个可以在游戏开始的时候调用一次,通过RequestCharactersInTexture函数,传入一个较大的字符串来使得unity扩大texture的大小。

另外如果游戏里所使用到的文字都是通过配置表来加入的,附送一个函数,来统计游戏中所有用到的文字,并生成上一函数需要的文字文本文件。

[MenuItem("Custom/Statistic Words")]
    public static void StatisticWords()
    {
        //用于统计字符
        Dictionary<char, int> wordMap = new Dictionary<char, int>();
        string[] txtFiles = Directory.GetFiles("Assets/Resources/Data/", "*.txt");
        for (int i = 0; i < txtFiles.Length; ++i)
        {
            Debug.Log("> open file: " + txtFiles[i]);
            string textContent = File.ReadAllText(txtFiles[i], System.Text.Encoding.UTF8);
            Debug.Log("> file " + txtFiles[i] + " size: " + textContent.Length);
            for (int wordIndex = 0; wordIndex < textContent.Length; ++wordIndex)
            {
                int useCount = 0;
                wordMap.TryGetValue(textContent[wordIndex], out useCount);
                wordMap[textContent[wordIndex]] = useCount + 1;
            }
        }
        
        Dictionary<char, int> sortedWordMap = new Dictionary<char, int>();
        sortedWordMap = (from entry in wordMap
                         orderby entry.Value descending
                         select entry).ToDictionary(pair => pair.Key, pair => pair.Value);
        IEnumerator enumerator = sortedWordMap.Keys.GetEnumerator();
        StringBuilder sBuilder = new StringBuilder();
        
        while (enumerator.MoveNext())
        {
            sBuilder.Append(string.Format("{0}:\t{1}\n", enumerator.Current,
                sortedWordMap[(char)enumerator.Current]));
        }
        File.WriteAllText("Assets/Resources/UI/Font/sortedChineseWords.txt",
            sBuilder.ToString(), Encoding.UTF8);
        sBuilder = new StringBuilder();
        enumerator = sortedWordMap.Keys.GetEnumerator();
        int wordCount = 0;
        while (enumerator.MoveNext()&&wordCount<800)
        {
            wordCount++;
            sBuilder.Append(enumerator.Current);
        }
        Debug.Log("> Total word: " + sBuilder.ToString().Length);
        File.WriteAllText("Assets/Resources/UI/Font/chineseWords.txt", sBuilder.ToString(),
            Encoding.UTF8);
    }

 如果有知道unity这个丢失字体真正原因的,欢迎告知。

 

ps: 上文中从Resources目录里取得文本文件及font文件,用的是我们自己实现的ResMngr,可自行更换成unity原来的方法

posted @ 2014-04-16 18:47  骑着单车滑翔  阅读(10154)  评论(0编辑  收藏  举报