使用BMFont创建适用于Unity的艺术字

最近经常使用艺术字,虽然之前的工作经验我知道只需要修什么哪些就可以弄好艺术字的创建和间隔,所以打算做个总结,接下来分为以下几步(其中会有补充,最后会有如何解决unity艺术字的字距问题)

第1步 下载BMFont

去官网下载即可BMFont官网,解压,64位就运行64位的exe程序

第2步 生成fnt文件

这里以0-9的数字图片为例子,图片如下:

打开之后,打开Options->Exprot Options,修改字体输出设置

至于内边距和间距一般不用管,然后打开Edit->Open Image Manager,点击Image,三个选项从上到下分别是导入图片、编辑图片(需要点击选中某行)、删除图片(同前一样需要选中)

这里点击导入图片,选中你的图片,假设你选的字符是0,那么选择好图片后,出现了这个页面,检查路径没问题,接下来是填入替换字符的id

如下图,鼠标放到替换字符处,前面的第一个就是id,该id为48,确定之后,开始选中这些需要导出的字符,亮色的就是选中的,左下角有你选中字符数

然后输出即可

补充:

BMFont官网文档

第三步 使用unity生成字体文件(.fontsettings)

添加脚本(非本人所写,这是我觉得写的不错的一个脚本)

,使用也很简单,只需要把.fnt和生成的图集一起导入unity,然后是三个参数的导入,fnt文件拖入第一个框内,第二个可以直接省略,第三个也可以省略,然后直接点击生成,字体就会出现在和fnt文件同目录下

文章链接:https://blog.csdn.net/w0100746363/article/details/105637683

cs 复制代码
using System.Collections.Generic;
using System.IO;
using System.Xml;
using UnityEditor;
using UnityEngine;

public class BMFont : EditorWindow
{
    private TextAsset _fontTextAsset;
    private Texture _fontTexture;
    private string _fontsDir;
 
    [MenuItem("FontTools/BMFont", false, 12)]
    private static void BMFontTools()
    {
        BMFont bmFont = new BMFont();
        bmFont.Show();
    }
 
    private string _getAssetPath(string path)
    {
        string pathTemp = path.Replace("\\", "/");
        pathTemp = pathTemp.Replace(Application.dataPath, "Assets");
        return pathTemp;
    }
 
    void OnGUI()
    {
        EditorGUILayout.BeginVertical();
        TextAsset taTemp = EditorGUILayout.ObjectField("选择Font文件:", _fontTextAsset, typeof(TextAsset), true) as TextAsset;
        if (taTemp != _fontTextAsset && taTemp != null)
        {
            string assetDir = Directory.GetParent(AssetDatabase.GetAssetPath(taTemp)).FullName;
            assetDir = _getAssetPath(assetDir);
            string imgPath = string.Format("{0}/{1}_0.png", assetDir, taTemp.name);
            _fontTexture = AssetDatabase.LoadAssetAtPath<Texture>(imgPath);
            _fontsDir = string.Format("{0}.fontsettings", Path.Combine(assetDir, taTemp.name));
            if (_fontTexture == null)
            {
                _fontsDir = string.Empty;
                Debug.LogError(string.Format("未发现{0}文件", imgPath));
            }
        }
        _fontTextAsset = taTemp;
 
        _fontTexture = EditorGUILayout.ObjectField("选择Font图片文件:", _fontTexture, typeof(Texture), true) as Texture;
 
        GUI.enabled = false;
        _fontsDir = EditorGUILayout.TextField("字体生成路径:", _fontsDir);
        GUI.enabled = true;
        if (GUILayout.Button("Generate Font"))
        {
            if (!string.IsNullOrEmpty(_fontsDir))
            {
                Material mat = AssetDatabase.LoadAssetAtPath<Material>(_fontsDir.Replace(".fontsettings", ".mat"));
                if (mat == null)
                {
                    mat = new Material(Shader.Find("UI/Default Font"));
                    AssetDatabase.CreateAsset(mat, _fontsDir.Replace(".fontsettings", ".mat"));
                }
                if (_fontTexture != null)
                {
                    mat = AssetDatabase.LoadAssetAtPath<Material>(_fontsDir.Replace(".fontsettings", ".mat"));
                    mat.SetTexture("_MainTex", _fontTexture);
                }
                else
                {
                    Debug.LogError("贴图未做配置,请检查配置");
                    return;
                }
 
                Font font = AssetDatabase.LoadAssetAtPath<Font>(_fontsDir);
                if (font == null)
                {
                    font = new Font();
                    AssetDatabase.CreateAsset(font, _fontsDir);
                }
 
                _setFontInfo(AssetDatabase.LoadAssetAtPath<Font>(_fontsDir),
                    AssetDatabase.GetAssetPath(_fontTextAsset),
                    _fontTexture);
                font = AssetDatabase.LoadAssetAtPath<Font>(_fontsDir);
                font.material = mat;
            }
            else
            {
                Debug.LogError("创建失败,请检查配置");
            }
        }
        EditorGUILayout.EndVertical();
    }
 
    private void _setFontInfo(Font font, string fontConfig, Texture texture)
    {
        XmlDocument xml = new XmlDocument();
        xml.Load(fontConfig);
        List<CharacterInfo> chtInfoList = new List<CharacterInfo>();
        XmlNode node = xml.SelectSingleNode("font/chars");
        foreach (XmlNode nd in node.ChildNodes)
        {
            XmlElement xe = (XmlElement)nd;
            int x = int.Parse(xe.GetAttribute("x"));
            int y = int.Parse(xe.GetAttribute("y"));
            int width = int.Parse(xe.GetAttribute("width"));
            int height = int.Parse(xe.GetAttribute("height"));
            int advance = int.Parse(xe.GetAttribute("xadvance"));
            CharacterInfo info = new CharacterInfo();
            info.glyphHeight = texture.height;
            info.glyphWidth = texture.width;
            info.index = int.Parse(xe.GetAttribute("id"));
            //这里注意下UV坐标系和从BMFont里得到的信息的坐标系是不一样的哦,前者左下角为(0,0),
            //右上角为(1,1)。而后者则是左上角上角为(0,0),右下角为(图宽,图高)
            info.uvTopLeft = new Vector2((float)x / texture.width, 1 - (float)y / texture.height);
            info.uvTopRight = new Vector2((float)(x + width) / texture.width, 1 - (float)y / texture.height);
            info.uvBottomLeft = new Vector2((float)x / texture.width, 1 - (float)(y + height) / texture.height);
            info.uvBottomRight = new Vector2((float)(x + width) / texture.width, 1 - (float)(y + height) / texture.height);
 
            info.minX = 0;
            info.minY = -height;
            info.maxX = width;
            info.maxY = 0;
 
            info.advance = advance;
 
            chtInfoList.Add(info);
        }
        font.characterInfo = chtInfoList.ToArray();
        AssetDatabase.Refresh();
    }
}

其中代码最关键的部分就是BMFont的uv坐标转换到unity下的uv坐标,这里代码的意思也很简单就是循环取出图集中的每张图(制作fnt字体时不是有张图吗,那个就是图集),然后每张图转换uv坐标即可。

BMFont的uv坐标,左上角(0,0),右下角为(宽度,高度)

Unity的uv坐标,左下角(0,0),右上角(1,1)

计算就如下图(自己打的手稿哈哈)

UV坐标是建立在一张图(纹理)上的。UV坐标是一个二维坐标系统,用于指定纹理图像上的具体位置,以便将纹理映射到三维模型的表面或二维图形上。这里的"一张图"指的是纹理图像,它包含了将要被映射的像素数据。

uv坐标参考博客:

Unity里的UV到底是什么 - cancantrbl - 博客园

Unity中Mesh的uv坐标讨论与使用方法_unity mesh uv-CSDN博客

解决unity艺术字的字距

通过 Tracking 设置可修改每个字符与同一行下一个字符的接近程度,而通过 Line spacing 设置可定义每行与下一行的接近程度

了解Font文件:Unity官网文档

注意

修改Tracking后需要运行(重新编译后才会生效)

相关推荐
ttod_qzstudio7 小时前
Unity中Mesh重叠顶点合并参考及其应用
unity·图形学
虾球xz7 小时前
游戏引擎学习第43天
学习·游戏引擎
虾球xz7 小时前
游戏引擎学习第45天
学习·游戏引擎
虾球xz1 天前
游戏引擎学习第42天
学习·游戏引擎
Little丶Seven1 天前
[游戏开发] Unity中使用FlatBuffer
数据库·unity
虾球xz1 天前
游戏引擎学习第44天
学习·算法·游戏引擎
rellvera1 天前
Unity使用脚本控制相机移动、旋转
数码相机·unity·游戏引擎
Thomas_YXQ2 天前
Unity3D项目为什么要使用FairyGUI
开发语言·unity·游戏引擎·unity3d·游戏开发
子燕若水2 天前
虚幻开发中的MYPROJECTFORPLUG_API
游戏引擎·虚幻