Cocos中,支持fnt格式的字体文件,但是Unity只支持ttf,和otf的字体文件,所以想用位图字体,就得自己造咯!!!
下图是我们想要的文字样式: 美工能给出的图片文件样式:
这里啰嗦一句,数字和点的图片高度最好一致,这样Text文字不会参差不齐。
一、使用BMFont工具,生成位图字体文件()
工具下载地址:http://www.angelcode.com/products/bmfont/
1. 点击 Options==>Export Options,修改导出配置
主要是Bit depth得改为32,Padding可改,可不改,Height本来为256,我修改为32,可以减去生成png中很大一片空白。
再说一下,Font descriptor,这里我选择的是Text。一般选择Text 或 XML,主要会影响到生成的fnt文件内容的格式,以及后面计算每个字符参数用到的解析方式。
2. 点击 Edit ===> Open Image manager,打开图片管理窗口
3. 点击 Image==>Import image... 导入图片,修改Id为与字符对应的Ascii码,例如0的Ascii码为48;
4. 图片导入完毕后,点击 Options==>Save bitmap font as... 导出字体文件(fnt&&png)
二、制作Unity中的Custom Font
1. 将fnt,png格式文件,导入Unity项目中
上面是默认的配置,之前我这边显示出错,网上有文章说png文件配置需要修改,比如Alpha Source改成Form Gray Scale、Sprite Mode改成 Mutiple等等。我尝试改了,也不顶用,实际上,成功的时候,啥也不用改,主要问题还是在计算字体文件item的UV(x,y,w,h)。
2. 再Editor文件夹下,新建BMFontEditor.cs文件
using UnityEngine;
using UnityEditor;
using System.Collections.Generic;
//用于生成 custom font 和 Meterial 文件
//并且配置字体中item的参数
public class BMFontEditor : EditorWindow
{
public TextAsset fontPosTbl;
public Texture fontTexture;
public Vector2 scrollPos;
struct ChrRect
{
public int id;
public int x;
public int y;
public int w;
public int h;
public int xofs;
public int yofs;
public int index;
public float uvX;
public float uvY;
public float uvW;
public float uvH;
public float vertX;
public float vertY;
public float vertW;
public float vertH;
public float width;
}
// add menu
[MenuItem("Tools/BMFontTools")]
static void Init()
{
EditorWindow.GetWindow(typeof(BMFontEditor));
}
// layout window
void OnGUI()
{
//EditorGUILayout.BeginScrollView(scrollPos);
EditorGUILayout.BeginVertical();
// use .fnt(.txt)
fontTexture = (Texture)EditorGUILayout.ObjectField("Font Texture", fontTexture, typeof(Texture), false);
EditorGUILayout.Space();
EditorGUILayout.LabelField("Use BMFont fnt File", EditorStyles.boldLabel);
EditorGUILayout.LabelField("(must Font Descriptor select Text)", EditorStyles.boldLabel);
fontPosTbl = (TextAsset)EditorGUILayout.ObjectField("BMFont fnt (.fnt)", fontPosTbl, typeof(TextAsset), false);
if (GUILayout.Button("Create(创建后必须重启生效)"))
{
if (fontTexture == null) this.ShowNotification(new GUIContent("No Font Texture selected"));
else if (fontPosTbl == null) this.ShowNotification(new GUIContent("No Font Position Table file selected"));
else
{
CalcChrRect(fontPosTbl, fontTexture);
}
}
EditorGUILayout.LabelField("(Must Restart unity valid!)", EditorStyles.whiteBoldLabel);
EditorGUILayout.LabelField("*********************************", EditorStyles.largeLabel);
EditorGUILayout.EndVertical();
//EditorGUILayout.EndScrollView();
}
void OnInspectorUpdate()
{
this.Repaint();
}
void CalcChrRect(TextAsset posTbl, Texture tex)
{
string fileName = AssetDatabase.GetAssetPath(fontPosTbl);
string texName = AssetDatabase.GetAssetPath(tex);
string fontName = System.IO.Path.GetFileNameWithoutExtension(fileName);
string fontPath = fileName.Replace(".fnt", ".fontsettings");
string matPath = fileName.Replace(".fnt", ".mat");
float imgw = (float)tex.width;
float imgh = (float)tex.height;
string txt = posTbl.text;
List tblList = new List();
foreach (string line in txt.Split('\n'))
{
if (line.IndexOf("char id=") == 0)
{
ChrRect d = GetChrRect(line, imgw, imgh);
tblList.Add(d);
}
}
if (tblList.Count == 0)
{
new GUIContent("Failed");
return;
}
ChrRect[] tbls = tblList.ToArray();
Font font = new Font();
font.name = fontName;
SetCharacterInfo(tbls, font);
Material mat = new Material(Shader.Find("UI/"));
mat.mainTexture = tex;
mat.name = fontName;
font.material = mat;
Debug.Log(System.IO.Path.GetFileNameWithoutExtension(fileName));
Debug.Log(fileName);
AssetDatabase.CreateAsset(mat, matPath);
AssetDatabase.CreateAsset(font, fontPath);
AssetDatabase.SaveAssets();
this.ShowNotification(new GUIContent("Complete"));
AssetDatabase.Refresh(ImportAssetOptions.ForceUpdate);
}
// over write custom font by new CharacterInfo
void SetCharacterInfo(ChrRect[] tbls, Font fontObj)
{
CharacterInfo[] nci = new CharacterInfo[tbls.Length];
for (int i = 0; i < tbls.Length; i++)
{
nci[i].index = tbls[i].index;
nci[i].advance = (int)tbls[i].width;
nci[i].uv.x = tbls[i].uvX;
nci[i].uv.y = tbls[i].uvY;
nci[i].uv.width = tbls[i].uvW;
nci[i].uv.height = tbls[i].uvH;
nci[i].vert.x = tbls[i].vertX;
nci[i].vert.y = tbls[i].vertY;
nci[i].vert.width = tbls[i].vertW;
nci[i].vert.height = tbls[i].vertH;
}
fontObj.characterInfo = nci;
}
// get font table one line. 重点在这
ChrRect GetChrRect(string line, float imgw, float imgh)
{
ChrRect d = new ChrRect();
foreach (string s in line.Split(' '))
{
if (s.IndexOf("id=") >= 0) d.id = GetParamInt(s, "id=");
else if (s.IndexOf("x=") >= 0) d.x = GetParamInt(s, "x=");
else if (s.IndexOf("y=") >= 0) d.y = GetParamInt(s, "y=");
else if (s.IndexOf("width=") >= 0) d.w = GetParamInt(s, "width=");
else if (s.IndexOf("height=") >= 0) d.h = GetParamInt(s, "height=");
else if (s.IndexOf("xoffset=") >= 0) d.xofs = GetParamInt(s, "xoffset=");
else if (s.IndexOf("yoffset=") >= 0) d.yofs = GetParamInt(s, "yoffset=");
else if (s.IndexOf("xadvance=") >= 0) d.width = GetParamInt(s, "xadvance=");
}
d.index = d.id;
d.uvX = (float)d.x / imgw;
d.uvY = (float)(imgh - (d.y)) / imgh;
d.uvW = (float)d.w / imgw;
d.uvH = (float)-d.h / imgh;
d.uvH = (float)d.h / imgh;
d.vertX = (float)d.xofs;
d.vertY = (float)-d.yofs;
d.vertW = d.w;
d.vertH = d.h;
return d;
}
// "wd=int" to int
int GetParamInt(string s, string wd)
{
if (s.IndexOf(wd) >= 0)
{
int v;
if (int.TryParse(s.Substring(wd.Length), out v)) return v;
}
return int.MaxValue;
}
}
然后,菜单栏会多出来一个Tools选项
3. 点击Tools==>BMFontTools,拖拽fnt和png文件
4. 点击Create,创建字体文件
以下是生成的Custom font 和 Meterial文件:5. 在工程中新建Text组件,将生成的字体文件,材质,拖到Text属性中
6. 调整Color,设置颜色值为图片中最浅的颜色
例如:根据我的图片,我就设置为金黄色部分颜色值,如果图片中白色,一般去白色部分的颜色值。然后结果就出来了:三、讲解细节
用txt文本打开fnt文件,看一下对应关系(这里是对应于png图片是原始图片,即没有做垂直翻转):
Index:char Id
Uv:
X: x/scaleW Y: 1 - y/scaleH
W: width/scaleW H: -height/scaleH
Vert :
X: xoffset Y: -yoffset
W: width H: height
Width: xadvance
最后要注意的几个点就是:
- 如果还没有显示的话,可能是Text组件的高度不够
- 如果换行发现字体重叠了,就修改字体文件属性Line Spacing的值
- 要改变字体大小,修改字号不会有用了,要修改Scale的x,y,最好修改为一样的比例,不然会被拉伸哦
- 有一种情况下,文字会是默认的黑色,需要调整文字颜色到相近的色号,才能达到渐变的效果,后来的测试中,拖了材质,就能显示出效果了,没有复现出之前的问题,只能记录一下了。