今天的任务是制作一个在NGUI和UGUI中可以使用的新字体,利用该新字体的文本可以正常显示在界面上,并且还支持中文字符的输入与显示。我在这里记录下制作过程,希望可以帮助到其他爱好者。
为什么要用字体集呢?简单说一下原因,如果我们使用电脑字体库里的某种字体,比如说黑体,我们把它当成资源导入到自己的项目中,它本身就占用内存就10M,打包的时候呢,也会把它打包进去,为了尽量减少内存,减少不必要的内存开销,我们可以制作自己的字体集。还有一个原因呢,就是我们在游戏里面可能会用的文字不会很多,有的字呢,用一次就够了,所以导入一个占用内存大的字体包,不如自己制作一个有限制的,只有我们自己需要使用到的字体包。另外,其实当我们在UILable组件上选择NGUI的字体集之后,输入字符之后,我们在屏幕上把它放大,我们会发现它会变模糊,其实它是把字体集中的字符都制作成NGUI的图集,当我们输入文字的时候,它会创建图集上相应的像素块。这样的好处是无论我们在UILable上写多少字体集中有的字符,它都会只占用一个DrawCall。
接下来讲述font字体的制作。
一、首先要创建字体,所以大家去找一下BitMap这个工具,用来生成字体的。然后打开这个软件,点击Options-FontSettings进行字体设置。
注意:
1.我在这里选用新宋体,大家可以自行选择,也可以下载第三方的ttf字体通过Add font file导入。
2.字体编码默认的是unicode,这个要注意。
接下来设置字体的导出选项:
注意:
1.Width和Height的值,4096算是比较大的了。最好不要超过这个值,不然做出来的图集太大,会加大drawcall的数量。
2.如果要做NGUI字体集,Font descripor选择Text,如果是UGUI,选择XML!!因为后边要解析这个字体文件。
二、创建一个txt文本,上网找一下中英文常用字,把他们粘贴进去(到时候制作好的字体,文本中有的字符才能被输入/显示)。编码格式转换成UTF-8。
然后保存,回到bmfont,点击Edit——Select chars from file,这样文本中的所有字符都被选中了,之后就点击Options——Save bitmap font as...得到两个文件。
注意:把fnt文件的后缀重命名为txt。好了,大功告成,把这两个导入到unity中就行了。
三、NGUI字体集的制作
先说NGUI的字体制作(比较简单),点击NGUI——Open——Font Maker就可以制作。如图:
type类型选择imported bitmap,把对应的myfont.txt文件和myfont_0.png托入对应位置。图集这里可选可不选,点击create the Font就可以生成对应资源了(生成了一个字体集prefab和材质.mat文件)。
最后在NGUI下创建一个Label,选择NGUI-Font,把生成的字体集prefab拖进去就可以像系统字体一样自由的使用了!大功告成。
四、UGUI字体集的制作
注意:UGUI字体集的制作要稍微麻烦一些,还是首先把两个文件导入到工程(这里注意,fnt文本文件导出时设置为xml格式,上面的注意中有提到这个)。
1.首先创建一个材质球,shader的模式改为GUI/Text Shader,将字体纹理(.png文件)添加上去。
2.创建font文件,右键Create——Custom Font创建。将材质添加到font上,line Spacing行距根据自己的实际情况去改变一下。
2.后面就是最重要的步骤,配置Character Rects,网上有相关公式,不过对于包含很多字体的fnt文件,手动配置实在是太麻烦,所有从网上搜到了一位网友写的自动解析方法,注意这个方法只适用于xml格式的fnt文件。
using UnityEngine;
using System.Collections;
using System.Xml;
using System;
public class CustomFontImportor : MonoBehaviour
{
public Font font;
public TextAsset textAsset;
void Awake()
{
if(font == null || textAsset == null)
{
Debug.LogError("请设置font和textAsset.");
return;
}
XmlDocument xmlDocument = new XmlDocument();
xmlDocument.LoadXml(textAsset.text);
int totalWidth = Convert.ToInt32(xmlDocument["font"]["common"].Attributes["scaleW"].InnerText);
int totalHeight = Convert.ToInt32(xmlDocument["font"]["common"].Attributes["scaleH"].InnerText);
XmlElement xml = xmlDocument["font"]["chars"];
ArrayList characterInfoList = new ArrayList();
for(int i = 0; i < xml.ChildNodes.Count; ++i)
{
XmlNode node = xml.ChildNodes[i];
if(node.Attributes == null)
{
continue;
}
int index = Convert.ToInt32(node.Attributes["id"].InnerText);
int x = Convert.ToInt32(node.Attributes["x"].InnerText);
int y = Convert.ToInt32(node.Attributes["y"].InnerText);
int width = Convert.ToInt32(node.Attributes["width"].InnerText);
int height = Convert.ToInt32(node.Attributes["height"].InnerText);
int xOffset = Convert.ToInt32(node.Attributes["xoffset"].InnerText);
int yOffset = Convert.ToInt32(node.Attributes["yoffset"].InnerText);
int xAdvance = Convert.ToInt32(node.Attributes["xadvance"].InnerText);
CharacterInfo info = new CharacterInfo();
Rect uv = new Rect();
uv.x = (float)x / totalWidth;
uv.y = (float)(totalHeight - y - height) / totalHeight;
uv.width = (float)width / totalWidth;
uv.height = (float)height / totalHeight;
info.index = index;
info.uvBottomLeft = new Vector2(uv.xMin, uv.yMin);
info.uvBottomRight = new Vector2(uv.xMax, uv.yMin);
info.uvTopLeft = new Vector2(uv.xMin, uv.yMax);
info.uvTopRight = new Vector2(uv.xMax, uv.yMax);
info.minX = xOffset;
info.maxX = xOffset + width;
info.minY = -yOffset - height;
info.maxY = -yOffset;
info.advance = xAdvance;
info.glyphWidth = width;
info.glyphHeight = height;
characterInfoList.Add(info);
}
font.characterInfo = characterInfoList.ToArray(typeof(CharacterInfo)) as CharacterInfo[];
Debug.Log("生成成功.");
}
}
使用方法也比较简单,拖到一个对象上面把自己创建的font和fnt字体文件拖拽到组件中,然后运行一下项目,即可生成,也可以改成Editor。最好可以看到完美的解析了出来
3.最后,在UGUI下创建一个Text,将创建的custom font文件拖拽到Font属性中,就可以自由使用了!大功告成。
注意:
在制作custom font的时候遇到点小问题,目前查阅了很多资料还没有很好解决,我不知道是不是这个功能还没有完善,还是自己在制作字体集的过程中出了一些差错,首先列出来这几个问题,后边慢慢填坑:
1.无法通过Size改变字体大小。 这可能是因为Custom Font本身无法改变字符大小,不过依然可以通过Scale来变相调节。
2.对于无法换行的问题,其实是可以通过修改Custom Font中的 Line Spacing 一项来解决该问题。
这些是我遇到的一些问题,也希望其他开发者有比较好的解决方案可以告诉我,万分感谢!