項目使用NGUI,最近碰到 Loading界面的提示文字破碎的Bug。
參考了以下文章
http://blog.csdn.net/langresser_king/article/details/22095235
轉自http://blog.csdn.net/huutu http://www.liveslives.com下面先來了解一下爲什麼會出現這種問題。
需要了解的是 NGUI的UILabel使用的是Unity 提供的Font 來作爲字體的輸入。
Unity對字體的生成是很節約的,這是很正常的,引擎應該都是這樣。
(1) 在Loading界面的 UILabel 上顯示 加載中 這三個字,那麼Unity就會生成這三個字的紋理,128x128 的FontTexture應該夠了。然後UILabel根據Font 去取每個字的圖形。
(2)然後 再打開一個界面,而這個界面上有很多字時,128x128的FontTexture 就不夠了,Unity會產生一張新的FontTexture,並且扔出一個回調。
(3)然後 NGUI的UILabel中處理這個回調,遍歷所有UILabel,把UILabel的內容全部Push到Font裏面去生成新的文字圖形到FontTexture。
static BetterList<UILabel> mList = new BetterList<UILabel>();
protected override void OnInit ()
{
base.OnInit();
mList.Add(this);
SetActiveFont(trueTypeFont);
}
//每次新建一個UILabel,都會讀取UILabel上面的內容,在FontTexture上添加一塊字體紋理。當FontTexture超過了原來的大小時,就會拋棄原來的FontTexture,用一個新的FontTexture,然後遍歷所有的UILabel,往新的FontTexture上添加字體紋理。
static void OnFontTextureChanged ()
{
for (int i = 0; i < mList.size; ++i)
{
UILabel lbl = mList[i];
if (lbl != null)
{
Font fnt = lbl.trueTypeFont;
if (fnt != null)
{
fnt.RequestCharactersInTexture(lbl.mText, lbl.mPrintedSize, lbl.mFontStyle);
}
}
}
//這段代碼讓UILabel重新讀取UV 重新渲染,下一幀文字就是正常的了
for (int i = 0; i < mList.size; ++i)
{
UILabel lbl = mList[i];
if (lbl != null)
{
Font fnt = lbl.trueTypeFont;
if (fnt != null)
{
lbl.RemoveFromPanel();
lbl.CreatePanel();
}
}
}
}
(4)最後UILabel被重新渲染。
字體破碎的情況,就出現在 (2) 這裏,UILabel 已經在渲染 進行時,然後Unity生成了一個新的FontTexture,這樣 當前幀 顯示出來的圖形肯定是有問題的。
那麼解決方法就是,在一開始的時候,就給Font 足夠多的文字,包括遊戲裏面所有的字都Push進去,這樣以後遊戲裏面都不用再Push了,FontTexture就可以用到老。
轉自http://blog.csdn.net/huutu http://www.liveslives.com
在UILabel 中新增函數
private static void DynamicFontBrokenFix(Font fnt)
{
if(fnt==null)
{
return;
}
if(fnt.characterInfo.Length<500)
{
string tmpStr = Resources.Load<TextAsset>("DynamicFontBrokenFix").text;
fnt.RequestCharactersInTexture(tmpStr, 32);
}
}
然後在設置字體的時候調用
protected void SetActiveFont (Font fnt)
{
if (mActiveTTF != fnt)
{
if (mActiveTTF != null)
{
int usage;
if (mFontUsage.TryGetValue(mActiveTTF, out usage))
{
usage = Mathf.Max(0, --usage);
if (usage == 0)
{
mActiveTTF.textureRebuildCallback = null;
mFontUsage.Remove(mActiveTTF);
}
else mFontUsage[mActiveTTF] = usage;
}
else mActiveTTF.textureRebuildCallback = null;
}
mActiveTTF = fnt;
DynamicFontBrokenFix(mActiveTTF);
if (mActiveTTF != null)
{
int usage = 0;
// Font hasn't been used yet? Register a change delegate callback
if (!mFontUsage.TryGetValue(mActiveTTF, out usage))
mActiveTTF.textureRebuildCallback = OnFontTextureChanged;
#if UNITY_FLASH
mFontUsage[mActiveTTF] = usage + 1;
#else
mFontUsage[mActiveTTF] = ++usage;
#endif
}
}
}
DynamicFontBrokenFix 是一個文本,裏面存放遊戲中所有的字。
轉自http://blog.csdn.net/huutu http://www.liveslives.com
意識到 這也是一個優化點,避免多次生成 FontTexture 。