Unity制作自定义字体的两种方法

论坛 期权论坛 脚本     
niminba   2021-5-23 04:30   2723   0

Unity支持自定义图片字体(CustomFont),网上有很多教程,细节不尽相同,当概括起来基本就是两种方式。一是使用BMFont,导出图集和.fnt文件,再使用图集在Unity中设置得到字体。二是不用BMFont,使用Unity自带的Sprite类似图集的功能。两种方式原理相同,只是手段有区别。基本原理都是先有一张贴图,比如:

需要知道的信息是贴图中每一个字符对应的ASCII码(例如0的ASCII码为48)与该字符在图集中对应的位置(0为x:0;y:0;w:55;h:76)。然后在Unity中创建材质和CustomFont并根据信息进行设置。

最后得到字体。

两种方式的区别仅在于第一步中如何得到图集的信息。具体的:

对于第一种使用BMFont的方式,目的是得到.fnt文件,实际上是xml格式文件。具体的信息为:

BMFont的使用方法不再详述。得到图集个fnt文件后,网上一般的方法是手动计算在Unity中的参数,有些繁琐,在这里写一个Editor脚本来自动完成这个过程。直接上代码:

using System;
using System.Collections.Generic;
using System.IO;
using System.Xml;
using UnityEditor;
using UnityEngine;
 
public class CreateFontFromFnt : EditorWindow
{
 [MenuItem("Tools/创建字体(Fnt)")]
 static void DoIt()
 {
  GetWindow<CreateFontFromFnt>("创建字体");
 }
 private string fontName;
 private string fontPath;
 private Texture2D tex;
 private string fntFilePath;
 
 private void OnGUI()
 {
  GUILayout.BeginVertical();
 
  GUILayout.BeginHorizontal();
  GUILayout.Label("字体名称:");
  fontName = EditorGUILayout.TextField(fontName);
  GUILayout.EndHorizontal();
 
  GUILayout.BeginHorizontal();
  GUILayout.Label("字体图片:");
  tex = (Texture2D)EditorGUILayout.ObjectField(tex, typeof(Texture2D), true);
  GUILayout.EndHorizontal();
 
  GUILayout.BeginHorizontal();
  if (GUILayout.Button(string.IsNullOrEmpty(fontPath) ? "选择路径" : fontPath))
  {
   fontPath = EditorUtility.OpenFolderPanel("字体路径", Application.dataPath, "");
   if (string.IsNullOrEmpty(fontPath))
   {
    Debug.Log("取消选择路径");
   }
   else
   {
    fontPath = fontPath.Replace(Application.dataPath, "") + "/";
   }
  }
  GUILayout.EndHorizontal();
 
  GUILayout.BeginHorizontal();
  if (GUILayout.Button(string.IsNullOrEmpty(fntFilePath) ? "选择fnt文件" : fntFilePath))
  {
   fntFilePath = EditorUtility.OpenFilePanelWithFilters("选择fnt文件", Environment.GetFolderPath(Environment.SpecialFolder.Desktop), new string[] { "", "fnt" });
   if (string.IsNullOrEmpty(fntFilePath))
   {
    Debug.Log("取消选择路径");
   }
  }
  GUILayout.EndHorizontal();
 
  GUILayout.BeginHorizontal();
  if (GUILayout.Button("创建"))
  {
   Create();
  }
  GUILayout.EndHorizontal();
 
  GUILayout.EndVertical();
 }
 
 private void Create()
 {
  if (string.IsNullOrEmpty(fntFilePath))
  {
   Debug.LogError("fnt为空");
   return;
  }
  if (tex == null)
  {
   Debug.LogError("字体图片为空");
   return;
  }
 
  string fontSettingPath = fontPath + fontName + ".fontsettings";
  string matPath = fontPath + fontName + ".mat";
  if (File.Exists(Application.dataPath + fontSettingPath))
  {
   Debug.LogErrorFormat("已存在同名字体文件:{0}", fontSettingPath);
   return;
  }
  if (File.Exists(Application.dataPath + matPath))
  {
   Debug.LogErrorFormat("已存在同名字体材质:{0}", matPath);
   return;
  }
  var list = new List<CharacterInfo>();
  XmlDocument xmlDoc = new XmlDocument();
  var content = File.ReadAllText(fntFilePath, System.Text.Encoding.UTF8);
  xmlDoc.LoadXml(content);
  var nodelist = xmlDoc.SelectNodes("font/chars/char");
  foreach (XmlElement item in nodelist)
  {
   CharacterInfo info = new CharacterInfo();
   var id = int.Parse(item.GetAttribute("id"));
   var x = float.Parse(item.GetAttribute("x"));
   var y = float.Parse(item.GetAttribute("y"));
   var width = float.Parse(item.GetAttribute("width"));
   var height = float.Parse(item.GetAttribute("height"));
 
   info.index = id;
   //纹理映射,上下翻转
   info.uvBottomLeft = new Vector2(x / tex.width, 1 - (y + height) / tex.height);
   info.uvBottomRight = new Vector2((x + width) / tex.width, 1 - (y + height) / tex.height);
   info.uvTopLeft = new Vector2(x / tex.width, 1 - y / tex.height);
   info.uvTopRight = new Vector2((x + width) / tex.width, 1 - y / tex.height);
 
   info.minX = 0;
   info.maxX = (int)width;
   info.minY = -(int)height / 2;
   info.maxY = (int)height / 2;
   info.advance = (int)width;
 
   list.Add(info);
  }
 
  Material mat = new Material(Shader.Find("GUI/Text Shader"));
  mat.R&V7B&V7BvBvBТFvBfV7Ff
分享到 :
0 人收藏
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

积分:1060120
帖子:212021
精华:0
期权论坛 期权论坛
发布
内容

下载期权论坛手机APP