Unity开发有时候很头疼的一个问题就是字体。一方面UGUI的字体性能实在是不佳,另一方面在现在游戏发行全球化的趋势下,多语言也是一个游戏所要去面对的问题。所幸,Unity自身也开始认知到字体的问题,所以收购了TextMeshPro并逐步开始取代Unity的字体实现。

这个系列不是原创,是从翻译文章,后面就不再每篇注明了。本系列阐述了TextMeshPro的强大之处,看完之后你就可以知道,它为何可以取代Unity这么久以来的字体方案。我们现在也正在使用这个方案,目前多语言的技术方案还没有完全落地,等到技术方案验证完毕之后会也会重新总结实战的多语言方案。目前预期是会分成两个大的模块:

  1. 多语言方案-字体统筹
  2. 多语言方案-语言文本

在这之前先放一点TMP的相关资料供大家学习:

TextMesh Pro 支持两种 text Objects。一种是Unity Unity's UI(UGUI),一种是放置在3D场景里的。他们的功能大体相同,但是会有一些本质的区别。这篇教程会使用UI Object的方式描述TextMesh Pro的功能,但是会指出所有和3D object上不同的地方。

1、Text Objects

和UGUI的text创建方法一样,你可以通过GameObject - UI - TextMeshPro - Text的方式创建一个TextMesh Pro 的 UI Text.新的物体拥有一个Rect Transform和一个 Canvas Renderer组件。但是它的Text是由Text Mesh Pro UGUI组件来管理。这里的UGUI 其实代表的是 Unity的GUI的意思。你也可以自己新建一个空的GameObject,然后给它添加Text Mesh Pro UGUI组件,那么它也会自动的添加其他所依赖的组件。如下图:

 

unity实现文字战斗 unity 文字游戏_unity实现文字战斗

1.1、UI Material

注意,对象的inspector面板也显示了用来渲染Text的Material。通常,UI objects都不会用这种方式显示他们的materials,因为它们是没有 Mesh Renderer组件的。但在这个例子中,它其实是UGUI组件的一部分。所以inspector显示也和UGUI Text的一致。如果你给这个物体添加更多的组件,那么将会显示在material的后面,除非你主动改变他们的顺序。

这个material 的inspector 提供了很方便的方式去访问text的材质,但是不太好的一点就是,UI层面的object的材质属性,不允许动态的变化。这也是TMP在UI层面上的一个技术限制。

1.2、3D Text Object

和UI的objects创建类似,3D的objects 可以通过 GameObject - 3D Object - TextMeshPro - Text的方式创建。text本身是平面的,就跟UI Text一样,不过不同的是,它是直接放置在3D Scene内,而不是一个Canvas下。

 

unity实现文字战斗 unity 文字游戏_unity实现文字战斗_02

在这个例子下,大家可以看到,它已经拥有了自己的Mesh Renderer组件了。它也有一个material 的inspector 显示了,不过不同的是,这里的材质属性是可以动态变化的了。

3D objects没有 Canvas Renderer组件,但是相应的,它有一个Text Container。它和Rect Transform组件协同工作,共同负责文本区域的各种布局。虽然这些已经是3D objects了,但是它仍然使用的是可以替换的Rect Transform组件。

2、Text Input Box

text input box 是用来解决用户自定义输入的控件。下面这个就是一个默认创建的text input box。

 

unity实现文字战斗 unity 文字游戏_3D_03

2.1、从右到左的显示方式

你可以通过开启RTL的编辑器Toggle来切换文字的显示模式。所有的文字在显示前都会变为倒序,inspector 的面板也会添加一个默认倒序的提示文字给你提供参考。

 

unity实现文字战斗 unity 文字游戏_Text_04

RTL 的模式只是颠倒了文字顺序,所有其他的设置都是相同的,比如你仍然可以使用右对齐的方式展示文字。它也不会执行文本替换之类的额外操作,这其实是为兼容阿拉伯文的显示方式。

3、Font 设置

fonts settings面板可以让你选择font并且自定义风格。它也包含了一些文字对齐以及其他的一些设置选项。

 

unity实现文字战斗 unity 文字游戏_3D_05

3.1、 Font Asset

TextMesh Pro 使用自己的font 资源和格式。后面会有专门的教程讲解,这里不细述。但是会给一个默认的字体 Arial SDF asset。

3.2、Material 预设置

每个字体都有一个默认的材质,但是你也可以为它创建自定义的材质。你可以通过一个下拉框快速选择一个材质的变体。

预制列表是通过搜索材质名称来匹配想要的材质的。一般是匹配对应font 资源名字,然后去匹配对应的font atlas texture。

3.3、Font Style

一共有7种字体样式的切换按钮可以用来调整text的外观。如果你想要文本的某一部分有特殊表现,那么就需要使用到富文本的标签了。(富文本也是有单独章节的教程)正常的字体。

 

unity实现文字战斗 unity 文字游戏_Text_06

最开始的两个是 黑体和斜体。他们的出现取决于font Asset。

 

unity实现文字战斗 unity 文字游戏_unity实现文字战斗_07

 

unity实现文字战斗 unity 文字游戏_Text_08

然后两个是启用下划线和删除线。

 

unity实现文字战斗 unity 文字游戏_unity实现文字战斗_09

 

unity实现文字战斗 unity 文字游戏_3D_10

前面4种风格是可以叠加设置的。

最后3个按钮,改变字母的大小写。第一个是全小写,第二个是全大写,第三个将所有的小写字母改为大写,但是字母的高度保持和小写字母一致。大概像这样:

 

unity实现文字战斗 unity 文字游戏_3D_11

下面三种风格是互斥的,但是可以和上面四种组合使用。

3.4、Color

Vertex colors用来改变文字的颜色。当然除了使用同一个颜色之外,你也可以通过开启gradient功能,让文字显示渐变颜色。给出四个角的颜色值之后,所有的字母都会呈现出渐变颜色。当然你可以给每个不同的text object设置不同的 gradient 颜色。(gradient color 也会有单独的章节教程)

 

unity实现文字战斗 unity 文字游戏_3D_12

 

unity实现文字战斗 unity 文字游戏_Text_13

渐变的颜色会与vertex color相乘,如果想得到一个原始的渐变色,那就需要把vertex color设置为白色。

如果 override tags 选项勾选了,那么Rich Text的样式和颜色就会被忽略了。

3.5、Font Size

Font Size定义了字符的显示大小。你可以使用一个固定大小的,也可以使用一个自动大小的。

如果 auto size启用的话,你只需要指定一个最大值和一个最小值,TextMesh Pro会根据实际的情况决定字符的Size,通过多次的布局直到发现最合适的青睐。最终的大小会在 font size 的输入区域内显示。

 

unity实现文字战斗 unity 文字游戏_UI_14

WD% 区域是包含字符宽度缩减的最大百分比,它会让一个字符变的瘦长,一般会用在数字上。

你可以通过调整line的高度来适应超大的字。可以在 Line 区域填写大小。

auto size如果开启的话,text在布局的时候,会进行调整很多次,以确保找到一个最合适的方式。所以如果不是有必要最好不要去使用,如果要使用也尽量避免去显示会频繁变化的文本。如果你的文本不需要变化,你其实可以使用auto size来找到最合适的字体大小,然后切换为固定字体来显示它。

3.6、Spacing Options

字符之间,行之间或者段落之间的空隙都是可以增加或者减少的。段落是由显示换行符定义的,你可以使用这些设置来微调你的文本显示,而不需要去改变font资源。

这些设置也可以通过使用Rich text 在单个 text object里进行更改。

3.7、Alignment

一共有10中对齐方式,分割成2个组,每个组之间是互斥的。

3.7.1、Horizontal

有四种水平的对齐模式可以选择。左、中间和右 模式控制显示区域内行的显示区域。这些模式不会改变每一行的内容,但是会改变每一行的水平位置。

下面分别是左对齐,中间对齐和右对齐的文字位置。

 

unity实现文字战斗 unity 文字游戏_UI_15

 

unity实现文字战斗 unity 文字游戏_unity实现文字战斗_16

 

unity实现文字战斗 unity 文字游戏_Text_17

justify 的对齐方式是用来表示拉伸,以确保能够填充满整行。主要是通过增加不同字符之间的间距来达到填充的目的。Wrap Mix的滑动条就是用来调整字符之间的额外间距。

 

unity实现文字战斗 unity 文字游戏_UI_18

Wrap mix 分别设置为0,1和默认0.4时候的样式。

 

unity实现文字战斗 unity 文字游戏_Text_19

 

unity实现文字战斗 unity 文字游戏_Text_20

 

unity实现文字战斗 unity 文字游戏_unity实现文字战斗_21

只有完整的行才会被拉伸,如果行中间发生了中断,或者在文字的末尾,都会按照左对齐的方式执行。

3.7.2、Vertical

有六种竖对齐的模式,顶、中间、和底部对齐,就像前面水平对齐的那三种一样,只不过这是在垂直方向的。

第四种方式是baseline,它定位内容,使第一行文本的基线与显示区域的中间对齐。当只有一行文本时,这可能比较有用。

第五种方式是midline ,它的行为类似于中间垂直对齐,但它使用文本网格的边界来确定垂直位置,而不是行高。

这在比较狭小的空间内比较有用,在ascender或者descender的时候不至于差距太大。

最后一种是 capline,它和baseline 比较像,但是是使用第一行文本的中间进行对齐。

3.8、Wrapping & Overflow

当 wrapping启用的时候,文字将会被自动换行。文字换行会确保它们的宽度不会超过显示区域,通常是会在某个单词结尾的时候进行换行,但是如果一个单词真的是太长了,也会被截断。

overflow通常在文本区域显示不下文字内容的时候发生。Overflow 意味着,文字将会超出它的显示边界。althrough 则会强制换行,Ellipsis 会被强制截断并且插入"…",Truncate 简单切掉显示不下的内容。

下面分别显示的是 Overflow, ellipsis, 和 truncate的情况。

 

unity实现文字战斗 unity 文字游戏_3D_22

 

unity实现文字战斗 unity 文字游戏_UI_23

 

unity实现文字战斗 unity 文字游戏_UI_24

Page 的模式会将文字单独裁减成适合显示的几个页面来适配选择区域。然后你可以选择显示哪一页。由于每一页的显示变成了独立的,所以垂直对齐就是基于每一个来进行作用了。你也可以使用Rich Text手动插入分页符达到同样的效果。

 

unity实现文字战斗 unity 文字游戏_Text_25

Masking的渲染方式和overflow比较像,但是所有在显示区域外的文字会被Shader隐藏。这个只在UI objects上有效,3D objects上无效。Scroll Rect 其实和这个是同样的表现,但是它不太受欢迎。

3.9、UV Mapping

你可以通过Shader使用一张额外的纹理贴图覆盖在文字之上。UV映射控制纹理的表现情况。每个维度都可以使用不同的设置。X维度或者是Y维度。

纹理的wrap mode应该设置为 repeat 不然 显示可能会不正确。

字符的纹理依据每个字符sprite,所以每个字符显示的是同一个Image,但是拉伸确实基于自己的宽高比。

Character–character mapping

 

unity实现文字战斗 unity 文字游戏_UI_26

Line 拉伸纹理是依据行的高和宽。(Line–line mapping)

 

unity实现文字战斗 unity 文字游戏_UI_27

Paragraph–paragraph mapping.

 

unity实现文字战斗 unity 文字游戏_UI_28

Match Aspect确保纹理在一个维上被缩放到它保持原来的纵横比。这可以确保纹理不会变形。纹理如何映射到文本是由另一个维度控制的,因此不能将两者都设置为匹配方面。

Character–match aspect mapping.

 

unity实现文字战斗 unity 文字游戏_unity实现文字战斗_29

UV offset可以用来调整纹理在X和Y方向的相对位置。当这些偏移被添加到纹理坐标中时,为了直观地向正方向移动纹理,将不得不应用负偏移量。

在使用Line或Paragraph 映射时,还有一个行偏移量,它被添加到每个连续行的X偏移量中。你可以用这个做倾斜变形。

Line–line mapping with offset

 

unity实现文字战斗 unity 文字游戏_Text_30

3.10、Kerning and Padding

kerning用来控制是否使用字体的字间距数据,这对于没有字间距数据的字体没有影响。

Extra padding 使渲染每个字符的sprites最大化。创建一些几何图形是为了适应可见的文本,但是这并不是每次都是完美契合的,在sprites 加入一些额外的填充来阻止多边形在sprite的边界被切割。

4、Extra Settings

Extra Settings的区域,包含了一些乱七八糟的小选项。

 

unity实现文字战斗 unity 文字游戏_UI_31

Margins的数值可以用给文本和内容边界之间添加一些空隙。你也可以使用一些负边距,这可能会导致文本超出文本框的边界之外。你也在场景视图里,通过拖拽的黄色矩形的方式来调整Margins。

 

unity实现文字战斗 unity 文字游戏_3D_32

Rich Text的功能是默认开启的,你可以根据需要手动关闭。那么所有的样式都不会被解析,直接原文呈现。

你可以自己勾选是否把text当做是 raycast target。如果禁用的话,UI会忽略鼠标或者点击事件。

Parse Escape Characters 如果开启的话,反斜杠转义字符会被解析为特殊的字符。所以\n就会换行,\t就会制表,等等。请注意,这适用于实际文本,如用户输入。但在代码中,会由编译器解析转义字符。

可以通过脚本限制多少个字符可见。这个可以用来模拟打字机效果。

Visible Descender控制底部垂直对齐的的工作方式,如果它开启了,文本会在底部显示,随着行被释放,文本会慢慢的向上推高。如果禁用的话,就正常的从上往下显示。

4.1、 3D Text Object

3D text objects有一些不同,它不包含margins 和 raycast-target 的设置。

 

unity实现文字战斗 unity 文字游戏_Text_33

Sorting Layer 和 Order settings用于微调对象的渲染顺序。

Orthographic 的选项用于 正焦摄像机的模式,防止字体产生透视。

默认的,quads用来显示字母。Volumetric Setup 激活另外一个模式,这种模式下使用多维数据集。这允许立体字符渲染,但目前还没有对此功能支持的着色器。

5、 Text Container

UI text object是依赖于UI canvas来确定它的位置和大小的,这是通过RectTransform 组件实现的。虽然3D text object也有RectTransform 组件,但是它并不能访问canvas 的布局系统。所以,它需要一个自己的容器组件。

 

unity实现文字战斗 unity 文字游戏_unity实现文字战斗_34

Anchor Position 和Dimensions 的设置,模仿画布的功能实现。

Margins 的一些数值也在这里进行设定,而不是在UI text object的Extra Settings里设置。