Unity/UI —— 使用字符图片自定义字体(Custom Font)

来源:互联网 发布:历史 知乎 编辑:程序博客网 时间:2024/06/05 02:58

前言

在Unity的UI设计中,我们经常会遇到需要自定义字体的情况。毕竟Unity自带的字体只有Arial一种,根本无法满足人民群众对于美的向往。当然,全能的Unity支持我们导入或创建字体,并可以在GUI Text和Text Mesh中使用。虽然可导入字体给我们提供了更多选择的余地,但也可能遇到选择的字体和游戏整体不搭或者仅需少量特定字符的情况。这种时候Custom Font就为我们自定义字体提供了方便,而设计这样一套字体其实只需要 一张 期望的图片即可做到。

素材准备

和导入的字体不同,Custom Font并不是通用的 .ttf/.otf 文件,而是由用户指定的包含特定字符的图片生成的。以数字字体为例,我们的原始素材可以是下面这样的一张图片:

digit1

这里字符图片的选取还是有一定讲究的,理想状态下的字符图应该满足以下几个条件:

  1. 图片格式为PNG格式(这样可以保证得到的图片背景为透明,方便在Unity中进行处理)
  2. 图片中字符颜色为白色(可选条件,如果没有 改变字体颜色 的需求该条件可以忽略)
  3. 每个字符以透明背景分割,并且以整齐的间距排列(方便识别每个具体字符的位置)
  4. 每个字符的大小一致(保证得到的字体整齐并且方便初始化配置)

当然,上述四个条件均为可选条件,但尽量做到上述几点可以让你之后的工作节省大量的时间。如果找到的素材不理想,建议先通过Photoshop进行一些简单的处理。

创建字体材质

当你经过第一步的处理获得理想的素材之后,下一步就是使用该素材创建一个字体材质。之前也说过Custom Font和导入字体的不同之处就在于它是由字符图片生成的。而字体材质就是一种特殊的材质(Material),你可以把它看做是链接Custom Font和字符图的纽带。 它接受一张字符图的纹理并可以被赋予给一个Custom Font,这也是我们之前强调字符图只能有一张的原因。创建一个字体材质的过程非常简单,在Project视图中右键单击 Create - Material,然后将其使用的着色器改为 “GUI/Text Shader”即可。正常情况下Inspector窗口下你可以看到下面的样子:

TextMaterial

直接将字符图片拖拽到Texture位置即可获得一个字体材质。我们同样可以在Project视图中右键单击 Create - Custom Font 来创建一个自定义字体,然后将之前得到的字体材质拖到Custom Font属性栏中的Material上就得到了一个Custom Font的雏形。显示效果如下图(根据Unity版本不同可能属性会有些许改变):

digitFont

进行字符映射

当然,经过上述步骤你得到的Custom Font还没有任何用处,因为它还没有进行最重要也是最麻烦的一个步骤,那就是将ASCII码与我们自定义的图片对应起来。

ASCII码,即America Standard Code for Information Interchange, 主要用于显示现代英语和其他西欧语言。属于Unity中Custom Font的默认编码集。我们使用Custom Font自定义字体的原理不过是简单地为我们需要的ASCII码指定一张图片,当使用该字体时,被指定了图片的字符可以正常显示,而未指定的字符或者不在ASCII编码集中的字符则无法显示,所以使用该方法定义数字或英文字母效果拔群,定义汉字字符貌似是不大行了。。。

首先选择我们之前导入的字符图片,将它的Texture Type 改为 Sprite(2D and UI),Sprite Mode改为 Multiple,点击Apply保存后我们就可以打开 Sprite Editor 对字符图进行编辑了。

Sprite Setting

关于纹理导入(Texture Importer)详细的相关配置问题,请参考Unity官方文档 Texture Importer。

在Sprite Editor窗口下,点击左上角的Slice按钮就可以对当前图片进行切分了,Unity会自动根据透明的背景识别每个字图片,即单个字符的图片。当然,我们这里的目的并不是使用这些被切分出来的字图片,而是使用每个字图片对应的参数来设置 Custom Font 中的 Character Rects 参数。

Sprite_Arguement

如上图所示, 被圈出来的Position和 Border信息对于我们之后指定该图片每个字符的位置具有重要的作用。此时打开我们之前创建的Custom Font 文件,我们可以在参数一栏中找到 Character Rects 这一选项,这也是Custom Font识别每个字符的重要配置信息。作为示范,我们可以先设置Character Rects 的Size为1,表示该字符集只包含一个字符(虽然一般不会有这种用法)。然而Unity并没有我们想象的那么高级,可以自动从图片中找出我们想要的字符图再映射到具体的ASCII码上,所以我们可以看到Unity希望我们为这唯一一个字符(即Element0)设置的参数列表,而我们必须每个参数都认真地设置才能看到效果。

Element0_Setting

不过不用慌,通过下面这张表你就可以基本掌握它们的意思并且快速地设置完成

参数名 换算公式 参数含义 Index 无 当前字符的索引, 用于确认该字符图对应的ASCII码,换算关系为 Ascii Start Offset + Index = Ascii实际值 Uv 无 该字符对应于图片中的哪个区域,四个参数取值范围均为[0,1],表示相对范围 Uv_X Position_X/Sprite_Width 字符图的起始x坐标 Uv_Y Postiion_Y/Sprite_Height 字符图的起始y坐标 Uv_W Position_W/Sprite_Width 字符图的相对宽度 Uv_H Position_H/Sprite_Height 字符图的相对高度 Vert 无 该字符对应于图片中的哪个区域,参数取值为实际像素值 Vert_X 一般为0 字符图在相对位置(即Uv_X基础上)的偏移, 以像素为单位 Vert_Y 一般为0 字符图在相对位置(即Uv_Y基础上)的偏移, 以像素为单位 Vert_W Position_W 字符图的实际宽度, 以像素为单位 Vert_H -Position_H 字符图的实际高度, 以像素为单位 Advanced(或Width) Position_W 字符图的宽度


对照表格完成设置之后,在使用对应ASCII码的字符时,Unity就可以帮助我们自动替换为图片。以该图片为例,我先在Sprite Editor中查找字符图“1”对应的位置信息,然后将计算的结果填入Custom Font中的Element0中。因为数字“1”对应于ASCII码中的49,所以我们可以直接设置index为49,并保持Ascii Start Offset为0;或者设置Ascii Start Offset为48,再将index设置为1。如果只设置数字的话,后一种方法显然更加方便。

Vert_H必须设置为实际像素的负值,这是因为Unity中图片是从左上角绘制的,所以高度实际上是向下生长。

digit1_setting

正常情况下数字“1”的显示效果如图中所示:

digit1_display

Custom Font的缺点和不足

Custom Font虽然给了用户自定义字体的能力,但比起常规的Dynamic Font还是有很多缺点的,例如:

  1. 无法定义中文字体。这点是由于Custom Font使用Ascii字符集导致的,Ascii字符集并不包含汉字。
  2. 无法通过Size改变字体大小。 就像上一节的演示图一样,数字“1”显然比Text文本框的范围还要高,这是因为Custom Font本身无法改变字符大小,不过依然可以通过Scale来变相调节
  3. 无法得到理想的字体颜色。 当改变Color,会在原图片的基础上变化,所以为了得到最好的显示效果,最好保证 字体颜色是白色,背景为透明
    4. 无法换行。关于为何无法换行。。。这个问题我也不清楚,哪位大哥能够解决这个问题请告诉我。可选的解决方案是使用多个文本框。

有热心的程序猿同僚私信告诉我可以通过调节Line Spacing实现换行功能,特别感谢这位陌生的朋友能指正我的错误~~

下面是对第四点的补充,其实是可以通过修改Custom Font中的 Line Spacing 一项来解决该问题。亲测有效,测试过程中有以下几点需要注意:
1. 直接修改Custom Font中的 Line Spacing 是不会导致Text重绘的,所以在调节的时候无法观察到Text发生变化,想要查看修改效果必须对Text组件进行修改(例如修改文本内容)。
2. UGUI内部Text组件是使用属性[ExecuteInEditMode]修饰的,使用该属性(attribute)会导致即使游戏未处于“播放”状态脚本也会运行,所以我们修改Text组件时,看到的内容也会实时更新。
3. 修改 Custom Font 的 Line Spacing 后,即使修改Scale也可以得到正常的效果。除此之外,还可以通过修改Text组件上的 Line Spacing 再次调整行间距。Text 组件上 Line Spacing 的计算单位就是Custom 中指定的 Line Spacing

原创粉丝点击