在我們游戲的開發過程中,在部分手機上運行游戲的時候,出現了字體丟失的問題,出問題的手機似乎用的都是高通芯片。
使用的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原來的方法