unity优化Unity教程合集Unity基础入门分享

UGUI图文混排

2017-02-22  本文已影响1055人  e497b7005759

无意间看见了这篇博文UGUI表情系统解决方案,作者的实现思路是重写Text的网格生成逻辑,把代表表情的文字网格替换输出为表情网格,从而实现文字和表情的混排。想起之前ngui做图文混排的2D方式(text+image),顿时觉得这种3D实现方式高大上。

细读了代码逻辑,发现有两处待完善的地方:
1.表情在换行处不能正确换行,这是因为基于表情文字符号(三个字符)的网格生成表情网格导致的。

1.png

2.表情动画帧数需要Shader从emoji_data读取,通过解析rgb去得到具体的帧数。这个实现有点绕,完全可以通过读取配置表emoji.txt的帧数,把值通过uv0传给Shader

基于第1点的不足,我换了另外一种方式去实现,主要是把表情符号从三个字符转化为一个汉字,把汉字的网格转化为表情网格,让Text自身去保证文字的排版,从而保证表情排版是正常的,上效果图及代码:

2.png

using UnityEngine; using UnityEngine.UI; using System.Collections; using System.Collections.Generic; using System.IO; using System.Text.RegularExpressions; using System.Text; public class EmojiTextComponent : Text { private const bool EMOJI_LARGE = true; private static Dictionary<string, EmojiInfo> EmojiIndex = null; struct EmojiInfo { public float x; public float y; public float size; public int len; } void Start() { SetEmojiText("[0]这是一个支持表情系统[1]的Emo[2],运行时支持动态表情。这是修改后的效果"); } Dictionary<int, EmojiInfo> emojiDic = new Dictionary<int, EmojiInfo>(); public void SetEmojiText(string emojiText) { if (EmojiIndex == null) { EmojiIndex = new Dictionary<string, EmojiInfo>(); string path = Application.streamingAssetsPath + "/emoji.txt"; using (StreamReader sr = new StreamReader(path)) { string line; bool isTitle = true; while ((line = sr.ReadLine()) != null) { if (isTitle) { isTitle = false; continue; } string[] strs = line.Split('\t'); EmojiInfo info; info.x = float.Parse(strs[3]); info.y = float.Parse(strs[4]); info.size = float.Parse(strs[5]); info.len = 0; EmojiIndex.Add(strs[1], info); } sr.Close(); } } emojiDic.Clear(); StringBuilder result = new StringBuilder(); MatchCollection matches = Regex.Matches(emojiText, "\\[[a-z0-9A-Z]+\\]"); int lastSubIndex = 0; for (int i = 0; i < matches.Count; i++) { EmojiInfo info; if (EmojiIndex.TryGetValue(matches[i].Value, out info)) { var matchItem = matches[i]; info.len = matchItem.Length; if (lastSubIndex != matchItem.Index) { result.Append(emojiText.Substring(lastSubIndex, matchItem.Index - lastSubIndex)); } emojiDic.Add(result.Length, info); result.Append("正"); lastSubIndex = matchItem.Index + matchItem.Length; } } if (lastSubIndex != emojiText.Length - 3) { result.Append(emojiText.Substring(lastSubIndex)); } text = result.ToString(); } readonly UIVertex[] m_TempVerts = new UIVertex[4]; protected override void OnPopulateMesh(VertexHelper toFill) { if (font == null) return; // We don't care if we the font Texture changes while we are doing our Update. // The end result of cachedTextGenerator will be valid for this instance. // Otherwise we can get issues like Case 619238. m_DisableFontTextureRebuiltCallback = true; Vector2 extents = rectTransform.rect.size; var settings = GetGenerationSettings(extents); cachedTextGenerator.Populate(text, settings); Rect inputRect = rectTransform.rect; // get the text alignment anchor point for the text in local space Vector2 textAnchorPivot = GetTextAnchorPivot(alignment); Vector2 refPoint = Vector2.zero; refPoint.x = Mathf.Lerp(inputRect.xMin, inputRect.xMax, textAnchorPivot.x); refPoint.y = Mathf.Lerp(inputRect.yMin, inputRect.yMax, textAnchorPivot.y); // Determine fraction of pixel to offset text mesh. Vector2 roundingOffset = PixelAdjustPoint(refPoint) - refPoint; // Apply the offset to the vertices IList<UIVertex> verts = cachedTextGenerator.verts; float unitsPerPixel = 1 / pixelsPerUnit; //Last 4 verts are always a new line... int vertCount = verts.Count - 4; toFill.Clear(); if (roundingOffset != Vector2.zero) { for (int i = 0; i < vertCount; ++i) { int tempVertsIndex = i & 3; m_TempVerts[tempVertsIndex] = verts[i]; m_TempVerts[tempVertsIndex].position *= unitsPerPixel; m_TempVerts[tempVertsIndex].position.x += roundingOffset.x; m_TempVerts[tempVertsIndex].position.y += roundingOffset.y; if (tempVertsIndex == 3) toFill.AddUIVertexQuad(m_TempVerts); } } else { for (int i = 0; i < vertCount; ++i) { EmojiInfo info; int index = i / 4; if (emojiDic.TryGetValue(index, out info)) { int tempVertsIndex = i & 3; m_TempVerts[tempVertsIndex] = verts[i]; m_TempVerts[tempVertsIndex].position *= unitsPerPixel; if (tempVertsIndex == 3) { //可动态设置offset值对表情大小进行控制 float offset = 4; m_TempVerts[0].position = m_TempVerts[0].position + new Vector3(-offset, offset); m_TempVerts[1].position = m_TempVerts[1].position + new Vector3(offset, offset); m_TempVerts[2].position = m_TempVerts[2].position + new Vector3(offset, -offset); m_TempVerts[3].position = m_TempVerts[3].position + new Vector3(-offset, -offset); m_TempVerts[0].uv1 = new Vector2(info.x, info.y + info.size); m_TempVerts[1].uv1 = new Vector2(info.x + info.size, info.y + info.size); m_TempVerts[2].uv1 = new Vector2(info.x + info.size, info.y); m_TempVerts[3].uv1 = new Vector2(info.x, info.y); toFill.AddUIVertexQuad(m_TempVerts); } } else { int tempVertsIndex = i & 3; m_TempVerts[tempVertsIndex] = verts[i]; m_TempVerts[tempVertsIndex].position *= unitsPerPixel; if (tempVertsIndex == 3) toFill.AddUIVertexQuad(m_TempVerts); } } } m_DisableFontTextureRebuiltCallback = false; } }

上一篇 下一篇

猜你喜欢

热点阅读