Unity中UGUI使用fnt位图字体

Cocos中,支持fnt格式的字体文件,但是Unity只支持ttf,和otf的字体文件,所以想用位图字体,就得自己造咯!!!

下图是我们想要的文字样式:
美工能给出的图片文件样式:
Unity中UGUI使用fnt位图字体_第1张图片

这里啰嗦一句,数字和点的图片高度最好一致,这样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文件内容的格式,以及后面计算每个字符参数用到的解析方式。

Unity中UGUI使用fnt位图字体_第2张图片

  2. 点击 Edit ===> Open Image manager,打开图片管理窗口
Unity中UGUI使用fnt位图字体_第3张图片
  3. 点击 Image==>Import image... 导入图片,修改Id为与字符对应的Ascii码,例如0的Ascii码为48;
Unity中UGUI使用fnt位图字体_第4张图片
  4. 图片导入完毕后,点击 Options==>Save bitmap font as... 导出字体文件(fnt&&png)
Unity中UGUI使用fnt位图字体_第5张图片

二、制作Unity中的Custom Font

  1. 将fnt,png格式文件,导入Unity项目中
Unity中UGUI使用fnt位图字体_第6张图片

    上面是默认的配置,之前我这边显示出错,网上有文章说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文件
Unity中UGUI使用fnt位图字体_第7张图片
Unity中UGUI使用fnt位图字体_第8张图片
  4. 点击Create,创建字体文件

    以下是生成的Custom font 和 Meterial文件:
  5. 在工程中新建Text组件,将生成的字体文件,材质,拖到Text属性中
Unity中UGUI使用fnt位图字体_第9张图片

   

  6. 调整Color,设置颜色值为图片中最浅的颜色

  例如:根据我的图片,我就设置为金黄色部分颜色值,如果图片中白色,一般去白色部分的颜色值。然后结果就出来了:

三、讲解细节

  用txt文本打开fnt文件,
Unity中UGUI使用fnt位图字体_第10张图片
fnt文件内容
Unity中UGUI使用fnt位图字体_第11张图片
CustomFont属性

看一下对应关系(这里是对应于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

最后要注意的几个点就是:

  1. 如果还没有显示的话,可能是Text组件的高度不够
  2. 如果换行发现字体重叠了,就修改字体文件属性Line Spacing的值
  3. 要改变字体大小,修改字号不会有用了,要修改Scale的x,y,最好修改为一样的比例,不然会被拉伸哦
  4. 有一种情况下,文字会是默认的黑色,需要调整文字颜色到相近的色号,才能达到渐变的效果,后来的测试中,拖了材质,就能显示出效果了,没有复现出之前的问题,只能记录一下了。

你可能感兴趣的:(Unity中UGUI使用fnt位图字体)