NGUI UILabel 文字破碎

項目使用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 。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章