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