using UnityEngine; using UnityEngine.UI; using System.Collections.Generic; using System.Text.RegularExpressions; using System.Text; using UnityEngine.Events; using UnityEngine.EventSystems; using LuaFramework; using LuaInterface; //[ExecuteInEditMode] public class InlieText : Text, IPointerClickHandler { /// /// 用正则取标签属性 名称-大小-宽度比例 /// private static readonly Regex m_spriteTagRegex = new Regex(@"", RegexOptions.Singleline); /// /// 需要渲染的图片信息列表 /// private List listSprite = new List(); /// /// 图片资源 /// private SpriteAsset m_spriteAsset; /// /// 标签的信息列表 /// private List listTagInfor = new List(); /// /// 图片渲染组件 /// private SpriteGraphic m_spriteGraphic; /// /// CanvasRenderer /// private CanvasRenderer m_spriteCanvasRenderer; #region 动画标签解析 //最多动态表情数量 int AnimNum = 1; List m_AnimIndex; Dictionary m_AnimSpiteTag; Dictionary m_AnimSpriteInfor; #endregion /// /// 初始化 /// protected override void OnEnable() { //在编辑器中,可能在最开始会出现一张图片,就是因为没有激活文本,在运行中是正常的。可根据需求在编辑器中选择激活... base.OnEnable(); //对齐几何 alignByGeometry = true; if (m_spriteGraphic == null) m_spriteGraphic = GetComponentInChildren(); if (m_spriteCanvasRenderer == null) m_spriteCanvasRenderer = m_spriteGraphic.GetComponentInChildren(); // if (AppFacade.Instance.GetManager(ManagerName.InlineSprite) != null) m_spriteAsset = AppFacade.Instance.GetManager(ManagerName.InlineSprite).m_spriteAsset; //启动的是 更新顶点 SetVerticesDirty(); } /// /// 在设置顶点时调用 /// 】、 //解析超链接 string m_OutputText; public override void SetVerticesDirty() { base.SetVerticesDirty(); //解析超链接 m_OutputText = text; //解析标签属性 listTagInfor = new List(); m_AnimIndex = new List(); m_AnimSpiteTag = new Dictionary(); foreach (Match match in m_spriteTagRegex.Matches(m_OutputText)) { if (m_spriteAsset == null) return; #region 解析动画标签 List tempListName = new List(); for (int i = 0; i < m_spriteAsset.listSpriteInfor.Count; i++) { //LogManager.Log((m_spriteAsset.listSpriteInfor[i].name + "_" + match.Groups[1].Value)); //if (m_spriteAsset.listSpriteInfor[i].name.Contains(match.Groups[1].Value)) if (m_spriteAsset.listSpriteInfor[i].name == match.Groups[1].Value) { tempListName.Add(m_spriteAsset.listSpriteInfor[i].name); break; } } if (tempListName.Count > 0) { SpriteTagInfor[] tempArrayTag = new SpriteTagInfor[tempListName.Count]; for (int i = 0; i < tempArrayTag.Length; i++) { tempArrayTag[i] = new SpriteTagInfor(); tempArrayTag[i].name = tempListName[i]; tempArrayTag[i].index = match.Index; float x = float.Parse(match.Groups[2].Value) * float.Parse(match.Groups[3].Value); float y = float.Parse(match.Groups[2].Value) * float.Parse(match.Groups[4].Value); tempArrayTag[i].size = new Vector2(x, y); tempArrayTag[i].Length = match.Length; } listTagInfor.Add(tempArrayTag[0]); m_AnimSpiteTag.Add(listTagInfor.Count - 1, tempArrayTag); m_AnimIndex.Add(listTagInfor.Count - 1); } #endregion } Vector2 extents = rectTransform.rect.size; } readonly UIVertex[] m_TempVerts = new UIVertex[4]; /// /// 绘制模型 /// /// protected override void OnPopulateMesh(VertexHelper toFill) { // base.OnPopulateMesh(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(m_OutputText, settings); Rect inputRect = rectTransform.rect; // LogManager.Log("size=" + extents.x + "_" + extents.y + "_" + inputRect); // get the text alignment anchor point for the text in local space Vector2 textAnchorPivot = GetTextAnchorPivot(alignment); Vector2 refPoint = Vector2.zero; refPoint.x = (textAnchorPivot.x == 1 ? inputRect.xMax : inputRect.xMin); refPoint.y = (textAnchorPivot.y == 0 ? inputRect.yMin : inputRect.yMax); //LogManager.Log(textAnchorPivot.x +"_"+ textAnchorPivot.y + " refPoint.x refPoint.y " + refPoint.x + "_" + refPoint.y); // Determine fraction of pixel to offset text mesh. Vector2 roundingOffset = PixelAdjustPoint(refPoint) - refPoint; //LogManager.Log("roundingOffset.x roundingOffset.y" + roundingOffset.x + "_" + roundingOffset.y); // Apply the offset to the vertices IList verts = cachedTextGenerator.verts; float unitsPerPixel = 1 / pixelsPerUnit; //Last 4 verts are always a new line... int vertCount = verts.Count - 4; toFill.Clear(); //清楚乱码 for (int i = 0; i < listTagInfor.Count; i++) { //UGUIText不支持标签,表现为乱码,我这里将他的uv全设置为0,清除乱码 for (int m = listTagInfor[i].index * 4; m < listTagInfor[i].index * 4 +4; m++) { UIVertex tempVertex = verts[m]; tempVertex.uv0 = Vector2.zero; verts[m] = tempVertex; } } //计算标签 其实应该计算偏移值后 再计算标签的值 算了 后面再继续改吧 // CalcQuadTag(verts); 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; // LogManager.Log(" m_TempVerts[tempVertsIndex].position.x m_TempVerts[tempVertsIndex].position.y" + m_TempVerts[tempVertsIndex].position.x + "_" + m_TempVerts[tempVertsIndex].position.y); if (tempVertsIndex == 3) toFill.AddUIVertexQuad(m_TempVerts); } //计算标签 计算偏移值后 再计算标签的值 //List vertsTemp = new List(); UIVertex[] vertsTemp = new UIVertex[vertCount]; for (int i = 0; i < vertCount; i++) { UIVertex tempVer=new UIVertex(); toFill.PopulateUIVertex(ref tempVer,i); //vertsTemp.Add(tempVer); vertsTemp[i] = tempVer; } CalcQuadTag(vertsTemp); m_DisableFontTextureRebuiltCallback = false; //绘制图片 DrawSprite(); #region 处理超链接的包围盒 // 处理超链接包围框 UIVertex vert = new UIVertex(); foreach (var hrefInfo in m_HrefInfos) { hrefInfo.boxes.Clear(); if (hrefInfo.startIndex >= toFill.currentVertCount) { continue; } // 将超链接里面的文本顶点索引坐标加入到包围框 toFill.PopulateUIVertex(ref vert, hrefInfo.startIndex); var pos = vert.position; var bounds = new Bounds(pos, Vector3.zero); for (int i = hrefInfo.startIndex, m = hrefInfo.endIndex; i < m; i++) { if (i >= toFill.currentVertCount) { break; } toFill.PopulateUIVertex(ref vert, i); pos = vert.position; if (pos.x < bounds.min.x) // 换行重新添加包围框 { hrefInfo.boxes.Add(new Rect(bounds.min, bounds.size)); bounds = new Bounds(pos, Vector3.zero); } else { bounds.Encapsulate(pos); // 扩展包围框 } } hrefInfo.boxes.Add(new Rect(bounds.min, bounds.size)); } #endregion } /// /// 解析quad标签 主要清除quad乱码 获取表情的位置 /// /// void CalcQuadTag(IList verts) { m_AnimSpriteInfor = new Dictionary(); //通过标签信息来设置需要绘制的图片的信息 listSprite = new List(); for (int i = 0; i < listTagInfor.Count; i++) { ////UGUIText不支持标签,表现为乱码,我这里将他的uv全设置为0,清除乱码 //for (int m = listTagInfor[i].index * 4; m < listTagInfor[i].index * 4 + 18*4; m++) //{ // UIVertex tempVertex = verts[m]; // tempVertex.uv0 = Vector2.zero; // verts[m] = tempVertex; //} InlineSpriteInfor tempSprite = new InlineSpriteInfor(); //获取表情的第一个位置,则计算他的位置为quad占位的第四个点 顶点绘制顺序: // 0 1 // 3 2 tempSprite.textpos = verts[((listTagInfor[i].index + 1) * 4) - 1].position; // LogManager.Log("tempSprite.textpos = " + tempSprite.textpos.x + "_" + tempSprite.textpos.y); // tempSprite.textpos.x += 165; //tempSprite.textpos.y += 40; //LogManager.Log("listTagInfor[i].size.x" + listTagInfor[i].size.x + "_" + listTagInfor[i].size.y); //设置图片的位置 tempSprite.vertices = new Vector3[4]; tempSprite.vertices[0] = new Vector3(0, 0, 0) + tempSprite.textpos; tempSprite.vertices[1] = new Vector3(listTagInfor[i].size.x, listTagInfor[i].size.y, 0) + tempSprite.textpos; tempSprite.vertices[2] = new Vector3(listTagInfor[i].size.x, 0, 0) + tempSprite.textpos; tempSprite.vertices[3] = new Vector3(0, listTagInfor[i].size.y, 0) + tempSprite.textpos; // LogManager.Log(listTagInfor[i].name + "_" + tempSprite.textpos.x + "_" + tempSprite.textpos.y + "_" + tempSprite.textpos.z); //LogManager.Log(tempSprite.vertices[0].x + "_" + tempSprite.vertices[0].y + "_" + tempSprite.vertices[0].z); // LogManager.Log(tempSprite.vertices[1].x + "_" + tempSprite.vertices[1].y + "_" + tempSprite.vertices[1].z); //LogManager.Log(tempSprite.vertices[2].x + "_" + tempSprite.vertices[2].y + "_" + tempSprite.vertices[2].z); // LogManager.Log(tempSprite.vertices[3].x + "_" + tempSprite.vertices[3].y + "_" + tempSprite.vertices[3].z); //计算其uv Rect spriteRect = m_spriteAsset.listSpriteInfor[0].rect; for (int j = 0; j < m_spriteAsset.listSpriteInfor.Count; j++) { //通过标签的名称去索引spriteAsset里所对应的sprite的名称 if (listTagInfor[i].name == m_spriteAsset.listSpriteInfor[j].name) { spriteRect = m_spriteAsset.listSpriteInfor[j].rect; break; } } Vector2 texSize = new Vector2(m_spriteAsset.texSource.width, m_spriteAsset.texSource.height); tempSprite.uv = new Vector2[4]; tempSprite.uv[0] = new Vector2(spriteRect.x / texSize.x, spriteRect.y / texSize.y); tempSprite.uv[1] = new Vector2((spriteRect.x + spriteRect.width) / texSize.x, (spriteRect.y + spriteRect.height) / texSize.y); tempSprite.uv[2] = new Vector2((spriteRect.x + spriteRect.width) / texSize.x, spriteRect.y / texSize.y); tempSprite.uv[3] = new Vector2(spriteRect.x / texSize.x, (spriteRect.y + spriteRect.height) / texSize.y); //声明三角顶点所需要的数组 tempSprite.triangles = new int[6]; listSprite.Add(tempSprite); #region 把每个表情的每一帧的sprite信息转化uv 顶点等可直接渲染的数据 if (m_AnimSpiteTag[i] != null) { SpriteTagInfor[] tempTagInfor = m_AnimSpiteTag[i]; InlineSpriteInfor[] tempSpriteInfor =new InlineSpriteInfor[tempTagInfor.Length]; for (int j = 0; j < tempTagInfor.Length; j++) { tempSpriteInfor[j] =new InlineSpriteInfor(); tempSpriteInfor[j].textpos = verts[((tempTagInfor[j].index + 1) * 4) - 1].position; //设置图片的位置 tempSpriteInfor[j].vertices = new Vector3[4]; tempSpriteInfor[j].vertices[0] = new Vector3(0, 0, 0) + tempSpriteInfor[j].textpos; tempSpriteInfor[j].vertices[1] = new Vector3(tempTagInfor[j].size.x, tempTagInfor[j].size.y, 0) + tempSpriteInfor[j].textpos; tempSpriteInfor[j].vertices[2] = new Vector3(tempTagInfor[j].size.x, 0, 0) + tempSpriteInfor[j].textpos; tempSpriteInfor[j].vertices[3] = new Vector3(0, tempTagInfor[j].size.y, 0) + tempSpriteInfor[j].textpos; //计算其uv Rect newSpriteRect = m_spriteAsset.listSpriteInfor[0].rect; for (int m = 0; m < m_spriteAsset.listSpriteInfor.Count; m++) { //通过标签的名称去索引spriteAsset里所对应的sprite的名称 if (tempTagInfor[j].name == m_spriteAsset.listSpriteInfor[m].name) newSpriteRect = m_spriteAsset.listSpriteInfor[m].rect; } Vector2 newTexSize = new Vector2(m_spriteAsset.texSource.width, m_spriteAsset.texSource.height); tempSpriteInfor[j].uv = new Vector2[4]; tempSpriteInfor[j].uv[0] = new Vector2(newSpriteRect.x / newTexSize.x, newSpriteRect.y / newTexSize.y); tempSpriteInfor[j].uv[1] = new Vector2((newSpriteRect.x + newSpriteRect.width) / newTexSize.x, (newSpriteRect.y + newSpriteRect.height) / newTexSize.y); tempSpriteInfor[j].uv[2] = new Vector2((newSpriteRect.x + newSpriteRect.width) / newTexSize.x, newSpriteRect.y / newTexSize.y); tempSpriteInfor[j].uv[3] = new Vector2(newSpriteRect.x / newTexSize.x, (newSpriteRect.y + newSpriteRect.height) / newTexSize.y); //声明三角顶点所需要的数组 tempSpriteInfor[j].triangles = new int[6]; } m_AnimSpriteInfor.Add(i, tempSpriteInfor); } #endregion } } //检测文本首行是否有表情 public bool CheckFirstLineHasFace() { //手动调用OnEnable(在父节点隐藏情况下,OnEnable不会执行,导致UpdateGeometry调用的方法中使用到的字段为null) if (!gameObject.activeInHierarchy) { OnEnable(); } UpdateGeometry(); // Debug.Log("@@@@@listSprite.Count@ :" + listSprite.Count + "@@@@@listTagInfor.Count@ :" + listTagInfor.Count); if (listSprite.Count > 0 && listTagInfor.Count > 0) { //计算第一个表情左下角距离文本矩形框顶部的距离是否小于等于表情本身高度 float deltay = preferredHeight / 2 - (listSprite[0].textpos.y + preferredHeight - rectTransform.sizeDelta.y); Debug.Log("@@@@@ deltay@ :" + deltay + "@@@@listTagInfor[0].size.y@@ :" + listTagInfor[0].size.y); if (deltay <= listTagInfor[0].size.y) { // Debug.Log("第一行有表情包"); return true; } } // Debug.Log("第一行没没没没咩有表情包"); return false; } /// /// 绘制图片 /// void DrawSprite() { Mesh m_spriteMesh = new Mesh(); if (listSprite.Count <= 0) { m_spriteCanvasRenderer.SetMesh(m_spriteMesh); m_spriteGraphic.UpdateMaterial(); return; } List tempVertices = new List(); List tempUv = new List(); List tempTriangles = new List(); for (int i = 0; i < listSprite.Count; i++) { for (int j = 0; j < listSprite[i].vertices.Length; j++) { tempVertices.Add(listSprite[i].vertices[j]); } for (int j = 0; j < listSprite[i].uv.Length; j++) { tempUv.Add(listSprite[i].uv[j]); } for (int j = 0; j < listSprite[i].triangles.Length; j++) { tempTriangles.Add(listSprite[i].triangles[j]); } } //计算顶点绘制顺序 for (int i = 0; i < tempTriangles.Count; i++) { if (i % 6 == 0) { int num = i / 6; tempTriangles[i] = 0 + 4 * num; tempTriangles[i + 1] = 1 + 4 * num; tempTriangles[i + 2] = 2 + 4 * num; tempTriangles[i + 3] = 1 + 4 * num; tempTriangles[i + 4] = 0 + 4 * num; tempTriangles[i + 5] = 3 + 4 * num; } } m_spriteMesh.vertices = tempVertices.ToArray(); m_spriteMesh.uv = tempUv.ToArray(); m_spriteMesh.triangles = tempTriangles.ToArray(); if (m_spriteMesh == null) return; m_spriteCanvasRenderer.SetMesh(m_spriteMesh); m_spriteGraphic.UpdateMaterial(); } #region 绘制每个表情的下一帧数据 float fTime = 0.0f; int iIndex = 0; void Update() { return; //暂时只需要渲染一帧的静态图片 所以不用update 日后要动态表情的话 再优化 fTime += Time.deltaTime; if (fTime >= 0.1f) { for (int i = 0; i < m_AnimIndex.Count; i++) { if (iIndex >= m_AnimSpriteInfor[m_AnimIndex[i]].Length) { listSprite[m_AnimIndex[i]] = m_AnimSpriteInfor[m_AnimIndex[i]][0]; } else { listSprite[m_AnimIndex[i]] = m_AnimSpriteInfor[m_AnimIndex[i]][iIndex]; } } DrawSprite(); iIndex++; if (iIndex >= AnimNum) { iIndex = 0; } fTime = 0.0f; } } #endregion #region 超链接 /// /// 超链接信息列表 /// private readonly List m_HrefInfos = new List(); /// /// 文本构造器 /// private static readonly StringBuilder s_TextBuilder = new StringBuilder(); /// /// 超链接正则 /// private static readonly Regex s_HrefRegex = new Regex(@"\n\s]+)>(.*?)()", RegexOptions.Singleline); private LuaFunction m_OnHrefClick = null; public void AddLinkEvent(LuaFunction func) { m_OnHrefClick = func; } /// /// 获取超链接解析后的最后输出文本 /// /// public string GetOutputText(string text) { s_TextBuilder.Length = 0; m_HrefInfos.Clear(); var indexText = 0; foreach (Match match in s_HrefRegex.Matches(text)) { s_TextBuilder.Append(text.Substring(indexText, match.Index - indexText)); //s_TextBuilder.Append(""); // 超链接颜色 var group = match.Groups[1]; var hrefInfo = new HrefInfo { startIndex = s_TextBuilder.Length * 4, // 超链接里的文本起始顶点索引 endIndex = (s_TextBuilder.Length + match.Groups[2].Length - 1) * 4 + 3, name = group.Value }; m_HrefInfos.Add(hrefInfo); s_TextBuilder.Append(match.Groups[2].Value); //s_TextBuilder.Append(""); indexText = match.Index + match.Length; } s_TextBuilder.Append(text.Substring(indexText, text.Length - indexText)); return s_TextBuilder.ToString(); } /// /// 点击事件检测是否点击到超链接文本 /// /// public void OnPointerClick(PointerEventData eventData) { Vector2 lp; RectTransformUtility.ScreenPointToLocalPointInRectangle( rectTransform, eventData.position, eventData.pressEventCamera, out lp); foreach (var hrefInfo in m_HrefInfos) { var boxes = hrefInfo.boxes; for (var i = 0; i < boxes.Count; ++i) { if (boxes[i].Contains(lp)) { if (m_OnHrefClick != null) { m_OnHrefClick.Call(hrefInfo.name, eventData.position.x, eventData.position.y); } return; } } } } protected override void OnDestroy() { if (m_OnHrefClick != null) { m_OnHrefClick.Dispose(); m_OnHrefClick = null; } } /// /// 超链接信息类 /// private class HrefInfo { public int startIndex; public int endIndex; public string name; public readonly List boxes = new List(); } #endregion } [System.Serializable] public class SpriteTagInfor { /// /// sprite名称 /// public string name; /// /// 对应的字符索引 /// public int index; /// /// 大小 /// public Vector2 size; public int Length; } [System.Serializable] public class InlineSpriteInfor { // 文字的最后的位置 public Vector3 textpos; // 4 顶点 public Vector3[] vertices; //4 uv public Vector2[] uv; //6 三角顶点顺序 public int[] triangles; }