ugui BMFont工具

发布时间 2023-06-29 00:57:59作者: yanghui01

最终效果

1) fnt文件上右击,执行命令

2) 空白位置右击,打开工具窗口生成fontsettings文件。

或者从菜单 -> Assets -> BMFont -> open BMFontTool打开

 

#if UNITY_EDITOR

using UnityEngine;
using UnityEditor;
using System.IO;
using System;

public class BMFontTool : EditorWindow
{

    const string MenuItemPath_Rebuild_fnt = "Assets/BMFont/Rebuild fnt";
    [MenuItem(MenuItemPath_Rebuild_fnt, true)]
    static bool AssetMenuItemValidator_Rebuild_fnt()
    {
        if (EditorApplication.isPlaying) return false;

        TextAsset selected = Selection.activeObject as TextAsset;
        if (selected == null) return false;

        var filePath = AssetDatabase.GetAssetPath(selected);
        return filePath.EndsWith(".fnt", StringComparison.OrdinalIgnoreCase);
    }

    [MenuItem(MenuItemPath_Rebuild_fnt)]
    static void AssetMenuItem_Rebuild_fnt()
    {
        TextAsset selected = Selection.activeObject as TextAsset;
        RebuildFnt(AssetDatabase.GetAssetPath(selected), selected.text);
    }


    [MenuItem("Assets/BMFont/open BMFontTool")]
    static void AssetMenuItem_OpenWin()
    {
        EditorWindow.GetWindow(typeof(BMFontTool));
    }


    private TextAsset m_FntText;

    void OnGUI()
    {
        EditorGUILayout.BeginVertical();

        EditorGUILayout.Space();

        m_FntText = (TextAsset)EditorGUILayout.ObjectField("BMFont fnt (.fnt)", m_FntText, typeof(TextAsset), false);
        if (GUILayout.Button("Rebuild fnt"))
        {
            if (null == m_FntText)
            {
                ShowNotification(new GUIContent("No Font Position Table file selected"));
                return;
            }
            RebuildFnt(AssetDatabase.GetAssetPath(m_FntText), m_FntText.text);
        }

        EditorGUILayout.EndVertical();
    }

    private static void RebuildFnt(string fntFilePath, string fntText)
    {
        var parse = FntParse.Parse(fntText);
        //parse.PrintInfo();

        var fntFileName = Path.GetFileNameWithoutExtension(fntFilePath);
        var fntFileDirPath = Path.GetDirectoryName(fntFilePath);
        //Debug.Log($"{fntFilePath}");
        //Debug.Log($"{fntFileDirPath}");

        var customFontFilePath = Path.Combine(fntFileDirPath, $"{fntFileName}.fontsettings");
        Font font = AssetDatabase.LoadMainAssetAtPath(customFontFilePath) as Font;
        if (null == font) //第1次生成
        {
            font = new Font();
            AssetDatabase.CreateAsset(font, customFontFilePath);
            AssetDatabase.WriteImportSettingsIfDirty(customFontFilePath);
            AssetDatabase.ImportAsset(customFontFilePath);
        }
        var fontMat = AssetDatabase.LoadAssetAtPath<Material>(customFontFilePath);
        if (null == fontMat)
        {
            fontMat = new Material(Shader.Find("UI/Default"));
            fontMat.name = "Font Material";
            AssetDatabase.AddObjectToAsset(fontMat, customFontFilePath);
            AssetDatabase.ImportAsset(customFontFilePath); // unity 5.4+ cannot refresh it immediately, must import it

            font.material = fontMat;
        }
        //更新字体图片
        var fntImageFilePath = Path.Combine(fntFileDirPath, parse.GetImageName(0));
        var fntImage = AssetDatabase.LoadMainAssetAtPath(fntImageFilePath) as Texture2D;
        UpdateFntImageSetting(fntImageFilePath);
        fontMat.mainTexture = fntImage;
        //字符信息
        font.characterInfo = parse.charInfos;

        SerializedObject so = new SerializedObject(font);
        //so.Update();
        so.FindProperty("m_FontSize").floatValue = Mathf.Abs(parse.fontSize);
        so.FindProperty("m_LineSpacing").floatValue = parse.lineHeight;
        so.FindProperty("m_Ascent").floatValue = parse.lineBaseHeight;

        //Descent在基线下, 所以是负值; Ascent+(-Descent)=fontSize
        SerializedProperty sp_Descent = so.FindProperty("m_Descent");
        if (sp_Descent != null)
            sp_Descent.floatValue = parse.lineBaseHeight - parse.lineHeight;
        Debug.Log($"ascent:{parse.lineBaseHeight}, descent:{parse.lineBaseHeight - parse.lineHeight}");
        UpdateKernings(so, parse.kernings);

        var b1 = so.ApplyModifiedProperties();
        var b2 = so.UpdateIfRequiredOrScript();
        so.SetIsDifferentCacheDirty();

        AssetDatabase.SaveAssets();
        AssetDatabase.Refresh(ImportAssetOptions.ForceUpdate);
        Debug.Log($"fnt finish: {b1}, {b2}");
    }

    private static void UpdateFntImageSetting(string fntImageFilePath)
    {
        TextureImporter texImporter = AssetImporter.GetAtPath(fntImageFilePath) as TextureImporter;
        //Debug.Log($"{fntImageFilePath}");
        texImporter.textureType = TextureImporterType.GUI;
        texImporter.mipmapEnabled = false;
        texImporter.SaveAndReimport();
    }

    private static void UpdateKernings(SerializedObject so, FntParse.Kerning[] kernings)
    {
        SerializedProperty sp_KerningValues = so.FindProperty("m_KerningValues");

        int oldKerningsCount = sp_KerningValues.arraySize;
        Debug.Log($"m_KerningValues: old count: {oldKerningsCount}");

        if (null == kernings || kernings.Length <= 0)
        {
            sp_KerningValues.ClearArray();
            return;
        }

        for (int i = 0; i < kernings.Length; i++)
        {
            if (i >= oldKerningsCount)
            {
                sp_KerningValues.InsertArrayElementAtIndex(i);
            }

            SerializedProperty sp_Kerning = sp_KerningValues.GetArrayElementAtIndex(i);
            var kerning = kernings[i];
            sp_Kerning.FindPropertyRelative("second").floatValue = kerning.amount;

            SerializedProperty sp_First = sp_Kerning.FindPropertyRelative("first");
            sp_First.Next(true); //第1次要true
            sp_First.intValue = kerning.first;
            sp_First.Next(false);
            sp_First.intValue = kerning.second;
        }
        //旧的比新的多, 多余的删掉
        for (int i = oldKerningsCount - 1; i >= kernings.Length; i--)
        {
            sp_KerningValues.DeleteArrayElementAtIndex(i);
        }
    }

}

#endif

 

关于为啥so.FindProperty("m_Ascent").floatValue = parse.lineBaseHeight;

 

参考

GitHub - litefeel/Unity-BitmapFontImporter: An unity editor extension for bitmap font.

unity隔一段时间再显示_解决 Unity 自定义字体垂直对齐问题_yang lebron的博客-CSDN博客