聊天是游戏中必不可少的功能,发送表情也是聊天系统的一个重要组成部分。笔者的项目中使用UGUI开发UI,在制作表情系统时也遇到了同样的问题,可是UGUI中的Text组件本身并不支持图文混编。为此,笔者提供了一套解决方案,供大家参考。

Unity推荐的方式是使用TextMesh解决混编问题。TextMesh的确可以实现混编,但是却存在和UGUI较难整合的问题(Mask遮罩、自适应等),同时也会因为使用多个材质导致无法使用动态批次合并。网上也有人使用Text+Image的形式来处理图文混编,但是需要解决排序等问题。最好的解决方案还是能让UGUI的Text能够自身支持图文混编。

通过查看UGUI的源代码和其Shader,可以重写Text生成Mesh的方法以及最终渲染的Shader,以此来实现图文混编的功能,后文会为大家一步步介绍实现方法。

整合表情图片

泰课在线

这是原始的表情资源,按照表情名_序列帧的形式统一命名,然后通过代码打成一张Atlas,为了能够支持动态表情,需要在Shader中使用UV动画,但是因为所有的表情都在一张Atlas中,帧数又不统一,因此需要再生成一张可以标识每一个表情有多少帧的数据贴图。
泰课在线
表情和数据Atlas,这两张图片会在最终渲染的Shader中使用。


当然还需要生成一张数据表,用户标识表情名和Text替代符的对应关系,以及每一个表情的UV位置。其中Key中的内容就是在Text中的表情替代符,至于为什么使用这种格式会在后面内容介绍。

重写Text中生成顶点的方法

这是比较关键的步骤,UGUI中Text生成顶点的规律是每个字符生成4个顶点,构成2个面。例如字符串:这是一个Text,在UGUI中会生成8x4=32个顶点,中文、英文、其他字符都是等价的,只是顶点之间的间距不同。因此可以在将表情替代符中的多个顶点修改成适合表情的4个顶点,使用第二套UV标识这部分顶点引用表情贴图,而非字体贴图。例如一个字符串:这里是表情[

泰课在线
读取配置文件,用于后面替换表情符。

泰课在线
利用正则表达式找出全部的表情符,并且匹配是否为系统所支持的表情符(上面读取的配置文件)。

泰课在线
重新生成顶点位置和UV坐标。

重写渲染部分

这是最后一步,重写一个Shader用来渲染。相较于原始Shader增添了几个新的属性。
泰课在线
其中_EmojiSize表示EmojiTexture每一行拥有几个表情,因为本示例中每一行有4个表情,所以这个位置填写4。其他的属性就不做阐述了。

泰课在线
引入第二套uv坐标。

泰课在线
VS几乎没多大变化,只是传递第二套UV坐标。

泰课在线
PS中先判断第二套UV坐标是否有数值,有数值则表明是表情,从_EmojiTex中绘制,从_EmojiDataTex中读取表情帧数,用于做uv动画。

泰课在线
至此,就实现了UGUI的表情系统,可以和原生的其他UGUI控件使用。同时因为只有一个材质,一个Pass,所以也可以进行动态批次合并。