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.SetTexture("_MainTex", tex);Font m_myFont = new Font();m_myFont.material = mat;AssetDatabase.CreateAsset(mat, "Assets" + matPath);AssetDatabase.CreateAsset(m_myFont, "Assets" + fontSettingPath);m_myFont.characterInfo = list.ToArray();EditorUtility.SetDirty(m_myFont);AssetDatabase.SaveAssets();AssetDatabase.Refresh();Debug.Log("创建成功!");}
}

使用起来很简单:

代码也没什么可深究的,目的是代替手动计算,只是在纹理映射的时候有一个小坑。

第二种方式使用Unity中的Sprite。Unity支持把一个Sprite切割成多个。可以用这种方式代替BMFont导出的fnt文件。需要手动做的工作是将图集的TextureType设置为Sprite,然后把SpriteMode设为Multiple,打开SpriteEditor,对图片进行切割。Slice就基本可以完成这个工作,如果需要再手动微调一下。

一张图按照字符的位置分割成了10个Sprite。然后选中每一个Sprite把Name设置成字符对应的ASCII码。这样第一种方法里fnt文件包含的信息基本都包含在这个“图集”里了。同样写一个Editor脚本把这些信息写入到CustomFont里面,并不用手动去创建。

using UnityEngine;
using UnityEditor;
using System.IO;public class CreateFont : EditorWindow
{[MenuItem("Tools/创建字体(sprite)")]public static void Open(){GetWindow<CreateFont>("创建字体");}private Texture2D tex;private string fontName;private string fontPath;private void OnGUI(){GUILayout.BeginVertical();GUILayout.BeginHorizontal();GUILayout.Label("字体图片:");tex = (Texture2D)EditorGUILayout.ObjectField(tex, typeof(Texture2D), true);GUILayout.EndHorizontal();GUILayout.BeginHorizontal();GUILayout.Label("字体名称:");fontName = EditorGUILayout.TextField(fontName);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("创建")){Create();}GUILayout.EndHorizontal();GUILayout.EndVertical();}private void Create(){if (tex == null){Debug.LogWarning("创建失败,图片为空!");return;}if (string.IsNullOrEmpty(fontPath)){Debug.LogWarning("字体路径为空!");return;}if (fontName == null){Debug.LogWarning("创建失败,字体名称为空!");return;}else{if (File.Exists(Application.dataPath + fontPath + fontName + ".fontsettings")){Debug.LogError("创建失败,已存在同名字体文件");return;}if (File.Exists(Application.dataPath + fontPath + fontName + ".mat")){Debug.LogError("创建失败,已存在同名字体材质文件");return;}}string selectionPath = AssetDatabase.GetAssetPath(tex);if (selectionPath.Contains("/Resources/")){string selectionExt = Path.GetExtension(selectionPath);if (selectionExt.Length == 0){Debug.LogError("创建失败!");return;}string fontPathName = fontPath + fontName + ".fontsettings";string matPathName = fontPath + fontName + ".mat";float lineSpace = 0.1f;//string loadPath = selectionPath.Remove(selectionPath.Length - selectionExt.Length).Replace("Assets/Resources/", "");string loadPath = selectionPath.Replace(selectionExt, "").Substring(selectionPath.IndexOf("/Resources/") + "/Resources/".Length);Sprite[] sprites = Resources.LoadAll<Sprite>(loadPath);if (sprites.Length > 0){Material mat = new Material(Shader.Find("GUI/Text Shader"));mat.SetTexture("_MainTex", tex);Font m_myFont = new Font();m_myFont.material = mat;CharacterInfo[] characterInfo = new CharacterInfo[sprites.Length];for (int i = 0; i < sprites.Length; i++){if (sprites[i].rect.height > lineSpace){lineSpace = sprites[i].rect.height;}}for (int i = 0; i < sprites.Length; i++){Sprite spr = sprites[i];CharacterInfo info = new CharacterInfo();try{info.index = System.Convert.ToInt32(spr.name);}catch{Debug.LogError("创建失败,Sprite名称错误!");return;}Rect rect = spr.rect;float pivot = spr.pivot.y / rect.height - 0.5f;if (pivot > 0){pivot = -lineSpace / 2 - spr.pivot.y;}else if (pivot < 0){pivot = -lineSpace / 2 + rect.height - spr.pivot.y;}else{pivot = -lineSpace / 2;}int offsetY = (int)(pivot + (lineSpace - rect.height) / 2);info.uvBottomLeft = new Vector2((float)rect.x / tex.width, (float)(rect.y) / tex.height);info.uvBottomRight = new Vector2((float)(rect.x + rect.width) / tex.width, (float)(rect.y) / tex.height);info.uvTopLeft = new Vector2((float)rect.x / tex.width, (float)(rect.y + rect.height) / tex.height);info.uvTopRight = new Vector2((float)(rect.x + rect.width) / tex.width, (float)(rect.y + rect.height) / tex.height);info.minX = 0;info.minY = -(int)rect.height - offsetY;info.maxX = (int)rect.width;info.maxY = -offsetY;info.advance = (int)rect.width;characterInfo[i] = info;}AssetDatabase.CreateAsset(mat, "Assets" + matPathName);AssetDatabase.CreateAsset(m_myFont, "Assets" + fontPathName);m_myFont.characterInfo = characterInfo;EditorUtility.SetDirty(m_myFont);AssetDatabase.SaveAssets();AssetDatabase.Refresh();//刷新资源Debug.Log("创建字体成功");}else{Debug.LogError("图集错误!");}}else{Debug.LogError("创建失败,选择的图片不在Resources文件夹内!");}}
}

这个脚本参考了某一篇博文,时间长了实在是找不到了。

原理跟第一种方法一样,只是计算细c#教程节略有差异。使用起来还是很简单:

大同小异的两种方法,个人更喜欢用第二种。不需要使用额外的软件,一键搞定,基本上可以丢给美术童鞋来做了。

以上就是本文的全部内容,希望对大家的学习有所帮助

Unity制作自定义字体的两种方法相关推荐

  1. Unity中制作自定义字体的两种方式

    Unity支持自定义图片字体(CustomFont),网上有很多教程,细节不尽相同,当概括起来基本就是两种方式.一是使用BMFont,导出图集和.fnt文件,再使用图集在Unity中设置得到字体.二是 ...

  2. unity 2D游戏开发 制作帧动画的两种方法

    本小主在这里给大家分享一下unity 2D游戏开发中制作帧动画的两种方法. 比较简单,一学即会. 方法一: 是用代码控制: 先创建一个2D工程.导入图片资源,并设置texture的texture ty ...

  3. Unity中ugui如何制作不规则按键的两种方法

    Unity中ugui如何制作不规则按键的两种方法 两种不同的方案 目前,关于这个问题如何,解决通过搜索引擎我们能找到两种不同的方案: 多边形碰撞器: 该方法是指给精灵(Sprite)添加一个多边形碰撞 ...

  4. BIGEMAP使用Unity3D制作真实地形的两种方法

    使用Unity3D制作真实地形的两种方法: 1.在SceneView中使用height tools直接绘制: 2.使用外部工具制作的heightmaps: 具体操作如下: 1.准备一块DEM数据,格式 ...

  5. 使用Unity3D制作真实地形的两种方法

    使用Unity3D制作真实地形的两种方法: 1.在SceneView中使用height tools直接绘制: 2.使用外部工具制作的heightmaps: 具体操作如下: 1.准备一块DEM数据,格式 ...

  6. 使用vivado调用自定义IP的两种方法

    使用vivado调用自定义IP的两种方法 方法一:采用Creat Block Design以图形化界面方式,即原理图方式调用自定义IP,例如下图: 方法二:采用代码方式,即类似函数方式调用自定义IP, ...

  7. 微信小程序使用自定义字体的三种方法

    一.loadFontFace接口 小程序官方提供的接口,最便捷的加载字体的方法,不过限制颇多.必须https且同源,canvas等原生组件不支持.注意!!使用本地文件无效,必须使用网络地址. 官方文档 ...

  8. Hexo自定义页面的两种方法

    原文地址:http://refined-x.com/2017/07/10/Hexo自定义页面的方法/. Hexo是静态页博客生成利器,同很多博主一样,前端路上原创技术博客也是使用Hexo生成并托管在G ...

  9. 微信小程序 使用特殊字体的两种方法

    微信小程序中如何使用特殊字体 我有两种方法: 1. 转base64格式 下载要使用的字体,建议TTF格式 打开网站 https://transfonter.org/ 转换格式,得到压缩包 将压缩包解压 ...

最新文章

  1. Linux学习之系统编程篇:守护进程(精灵进程、后台进程)
  2. Decision Tree学习笔记(基础篇)
  3. 反射实体自动生成EasyUi DataGrid模板 第二版--附项目源码
  4. 科技英语翻译计算机化考试,2017年英语四级翻译范文之考公热
  5. Go实现Raft第三篇:命令和日志复制
  6. tomcat配置请求指定html文件路径,Tomcat8限制指定域名或者IP访问(示例代码)
  7. 95-231-020-源码-Chain简介
  8. win10更新后开不了机_坚决不更新!被微软雪藏的win10系统版本,只要3GB,老爷机的克星!...
  9. [CSS备忘] css3零散
  10. JavaScript设计模式之装饰者模式
  11. 解决引用微信公众号获取的图片不能正常显示的问题,显示改图片来自微信公众号
  12. SVD奇异值分解简述
  13. Idea 常用设置和快捷键
  14. CTSCAPIOTHUPC2018颓废记
  15. xposed伪造收到短信
  16. t - 分布的区间估计
  17. Gilbreath原理中的数学与魔术(二)——Ultimate Gilbreath 原理 Mandelbrot 集合
  18. 矿大计算机学院徐慧,【导师制进行时】徐慧:给学生一个选择的权利
  19. 眼睛慢慢眯成一条线的人都是实力很强劲的,教你在Unity中通过BlendShape来实现角色面部表情过渡切换(Animation)
  20. Java 属性集合Properties的六种遍历处理方式

热门文章

  1. 量化投资学习-27:突破前期高点,才是突破禁锢,放飞自我的开始
  2. win10安装Ubuntu20.04虚拟机
  3. 绝缘监测产品在船舶岸电的应用
  4. 在OpenCV里实现导向滤波
  5. 小程序反编译windows辅助脚本
  6. ubuntu安装mysql ERROR 1045 (28000): Access denied for user 'root'@'localhost' (using password: YES
  7. python图像特征点匹配
  8. 使用putty从windows向远程服务器传递文件
  9. 网络战利器——“网络安全态势感知”
  10. 《搜索引擎优化 SEO 知识完全手册》完整版2