NGUI所见即所得之UIFont , UIFontMaker
在上一篇博客介绍了UIAtlas的结构和UIAtlasMaker生成Atlas的原理(NGUI所见即所得之UIAtlasMaker , UIAtlas),按照介绍UIAtlas的行为脉络,应该先对UIFont进行介绍,但是发现UIFont这个脚本特别长有点被吓到了,这主要是因为之前都没有怎么用过UIFontMaker,只是创建Dynamic字体很简单,然后又一个改进是不用再对不同字体大小生成不同的预设,现在只需要TTF和设置字体大小就可以了,方便直观多了,看下图:FontMaker界面
既然从代码理出点头绪出来比较困难,UIFont的成员变量太多了,只有先玩下FontMaker,因为Dynamic字体已经不用创建了,只需要改下Font Type为Dynamic就可以了,所以只要看下Bitmap的形式就差不多了: Font Data其实每个字在指定Texture的偏移已经大小等信息(Font Data可以由BM Font等软件生成),看下Output栏。选择UIFont就是把新生成的字体加入选择的UIFont中去,至于Atlas选项很重要(因为看到DrawCall),就是把Texture的图片放进选择的Atlas中去,减少DrawCall。
进过上面的操作,对UIFont一堆的成员变量就不会莫名其妙了,这也是因为UIFont糅合了比较多的东西,所以会复杂些。
UIFontMaker
下面还是先看下UIFontMaker,人的思维都习惯从易到难,所以会学习一定是最注重循序渐进的,好了不废话了,切入正题。先看下MakeAsChanged():
C#代码 void MarkAsChanged () { if (NGUISettings.font != null) { List<UILabel> labels = NGUIEditorTools.FindAll<UILabel>(); foreach (UILabel lbl in labels) { if (lbl.bitmapFont == NGUISettings.font) { lbl.bitmapFont = null; lbl.bitmapFont = NGUISettings.font; } } } }做为开胃菜,这个函数很简单,就是替换UILabel的UIFont,也就说当前对NGUISettings.font进行修改,而上面UIFontMaker的见面只有一个Select是对UIFont进行更改的(加入新生成的字体),所以很自然可以猜到MakeAsChange这个函数只有在Select选择了UIFont的情况下才会被调用执行。
C#代码 static void CreateFont (UIFont font, int create, Material mat) { if (create == 1) { // New dynamic font font.atlas = null; font.dynamicFont = NGUISettings.dynamicFont; font.dynamicFontStyle = NGUISettings.dynamicFontStyle; } else { // New bitmap font font.dynamicFont = null; BMFontReader.Load(font.bmFont, NGUITools.GetHierarchy(font.gameObject), NGUISettings.fontData.bytes); if (create == 2) { font.atlas = null; font.material = mat; } else if (create == 3) { font.sPRiteName = NGUISettings.fontTexture.name; font.atlas = NGUISettings.atlas; } } }
最主要的是BMFontReader.Load,然后可以进一步看下BMFontReader,BMFont,BMGlphy这三个脚本,其实看到这三个脚本的注释可以发现,其实NGUI就是把BMFont移植过来:
BMFont reader. C# implementation of http://www.angelcode.com/products/bmfont/
由于篇幅和主题,这里就不做介绍了,但是至少可以认识了字体制作方法,下次可以自己写一个美术字体的制作程序。
剩下的OnGUI就没有什么必要介绍的,只是一个条件的跳转和细节的判断。
UIFont
看到UIFontMaker的界面操作(选择项比较多),就知道UIFont的成员变量或属性会多出一些,其中mMat,mReplacement mSprite在UIAtlas中也有,就不做解释了。
C#代码 [HideInInspector][SerializeField] Material mMat; [HideInInspector][SerializeField] Rect mUVRect = new Rect(0f, 0f, 1f, 1f); [HideInInspector][SerializeField] BMFont mFont = new BMFont(); [HideInInspector][SerializeField] int mSpacingX = 0; [HideInInspector][SerializeField] int mSpacingY = 0; [HideInInspector][SerializeField] UIAtlas mAtlas; [HideInInspector][SerializeField] UIFont mReplacement; [HideInInspector][SerializeField] float mPixelSize = 1f; // List of symbols, such as emoticons like ":)", ":(", etc [HideInInspector][SerializeField] List<BMSymbol> mSymbols = new List<BMSymbol>(); // Used for dynamic fonts [HideInInspector][SerializeField] Font mDynamicFont; [HideInInspector][SerializeField] int mDynamicFontSize = 16; [HideInInspector][SerializeField] FontStyle mDynamicFontStyle = FontStyle.Normal; // Cached value UISpriteData mSprite = null; int mPMA = -1; bool mSpriteSet = false; // I'd use a Stack here, but then Flash export wouldn't work as it doesn't support it static BetterList<Color> mColors = new BetterList<Color>();
下面对部分变量做下注释性的介绍:
mUVRect
C#代码 public Rect uvRect { get { if (mReplacement != null) return mReplacement.uvRect; if (mAtlas != null && (mSprite == null && sprite != null)) { Texture tex = mAtlas.texture; if (tex != null) { mUVRect = new Rect( mSprite.x - mSprite.paddingLeft, mSprite.y - mSprite.paddingTop, mSprite.width + mSprite.paddingLeft + mSprite.paddingRight, mSprite.height + mSprite.paddingTop + mSprite.paddingBottom); mUVRect = NGUIMath.ConvertToTexCoords(mUVRect, tex.width, tex.height); #if UNITY_EDITOR // The font should always use the original texture size if (mFont != null) { float tw = (float)mFont.texWidth / tex.width; float th = (float)mFont.texHeight / tex.height; if (tw != mUVRect.width || th != mUVRect.height) { //Debug.LogWarning("Font sprite size doesn't match the expected font texture size./n" + // "Did you use the 'inner padding' setting on the Texture Packer? It must remain at '0'.", this); mUVRect.width = tw; mUVRect.height = th; } } #endif // Trimmed sprite? Trim the glyphs if (mSprite.haspadding) Trim(); } } return mUVRect; } set { if (mReplacement != null) { mReplacement.uvRect = value; } else if (sprite == null && mUVRect != value) { mUVRect = value; MarkAsDirty(); } } }很长一段代码,mUVRect表示的文字集的图片在图集的偏移和长宽。
针对UILabel提供三种显示类型,UIFont提供了三种计算字符串Dimension(像素)的下面三个方法,这三个方法也占用了UIFont相当大的篇幅:
public Vector2 CalculatePrintedSize (string text, int size, bool encoding, SymbolStyle symbolStyle)
public string GetEndOfLineThatFits (string text, int size, int lineWidth, bool encoding, SymbolStyle symbolStyle)
public int CalculateOffsetToFit (string text, int size, int lineWidth, bool encoding, SymbolStyle symbolStyle)
BMSymbol
很早就看到说NGUI支持表情输入,虽然之前项目中,看到同事做聊天框用的是NGUIHtml这个插件来实现的,但是这样的话,不是让NGUI不得极其用,有点小浪费,其实原理就是根据符号的字符串找到图片。
小结:
今天晚上,一开始看到UIFont这么行代码就有点畏难,后面看了点视频,觉得还是接着写吧,虽然BMFont和BMSymbol的部分几乎没有介绍,原因有两个:1)如果实际项目中不是自己动手写NGUI插件没有太多必要,2)现在已经凌晨2:10了时间有点晚,以前在学校都没觉得什么,现在工作了,觉得码农都是一个高危职业,身体是自己的,所以自己一再强调要早点休息(虽然还是到了这个时候,原谅我吧),说真的现在头还真有点晕。
刚突然听到Beyond的《不再犹豫》无聊望见了犹豫,达到理想不太易,即使有信心,斗志却抑止”很深刻的刻画了我一直以来的状态,所以才坚持写完的,加油,努力!
如果您对D.S.Qiu有任何建议或意见可以在文章后面评论,或者发邮件(gd.s.qiu@Gmail.com)交流,您的鼓励和支持是我前进的动力,希望能有更多更好的分享。
转载请在文首注明出处:http://dsqiu.iteye.com/blog/1968002
更多精彩请关注D.S.Qiu的博客和微博(ID:静水逐风)
晚安,明天早起跑步去!
新闻热点
疑难解答