using UnityEngine; using UnityEngine.UI; using System.Linq; using System.Collections; using System.Collections.Generic; using System.Text; public class ImageInfo { public int Left; public int Right; public SpriteInfo SpriteInfo; } public class TextPlus : Text { #region 变量 public ImagePlus ImagePlus { get { if (ImagePlus_ == null) { ImagePlus_ = GetComponentInChildren(); if (ImagePlus_ == null) { GameObject go = new GameObject("ImagePlus", typeof(ImagePlus)); RectTransform tra = go.GetComponent(); tra.SetParent(rectTransform); } } return ImagePlus_; } set { ImagePlus_ = value; } } private ImagePlus ImagePlus_; public bool Draw; public bool SetY = false; public float Y = 0; public float LineHeight; public float MaxLineHeight = Mathf.Infinity; public VertexHelper ToFill; public List RemovePos = new List(); public List ImageIndex = new List(); public List RemoveIndex = new List(); public List NewTextIndex = new List(); public List NewTextPos = new List(); public List TextVertex = new List(); public List ImageVertex = new List(); #endregion protected override void OnPopulateMesh(VertexHelper toFill) { base.OnPopulateMesh(toFill); List imageList = GetImageList(); if (imageList.Count == 0) { Draw = false; } else { Draw = true; } if (Draw) { Draw = false; ToFill = toFill; Initialize(); for (int i = 0; i < imageList.Count; i++) { for (int j = imageList[i].Left; j <= imageList[i].Right; j++) { ClearChar(j); } RemoveChar(imageList[i]); CreateImage(imageList[i]); } for (int i = 0; i < RemovePos.Count; i++) { NewTextPos.RemoveAt(RemovePos[i] - i); } for (int i = 0; i < RemoveIndex.Count; i++) { NewTextIndex.RemoveAt(RemoveIndex[i] - i); } #region 调试 //for (int i = 0; i < NewTextPos.Count; i+=6) //{ // Debug.Log(NewTextPos[i] + " " + NewTextPos[i + 1] + " " + NewTextPos[i + 2] + " " + NewTextPos[i + 3] + " " + NewTextPos[i + 4] + " " + NewTextPos[i + 5]); //} //for (int i = 0; i < NewTextIndex.Count; i++) //{ // Debug.Log(NewTextIndex[i]); //} //for (int i = 0; i < ImageIndex.Count; i++) //{ // Debug.Log(ImageIndex[i]); //} #endregion Retract(); for (int i = 0; i < ImageIndex.Count; i++) { UIVertex v0 = ImageVertex[0 + i*4]; UIVertex v1 = ImageVertex[1 + i*4]; UIVertex v2 = ImageVertex[2 + i*4]; UIVertex v3 = ImageVertex[3 + i*4]; v0.position = NewTextPos[0 + (ImageIndex[i] - i)*6]; v1.position = NewTextPos[1 + (ImageIndex[i] - i)*6]; v2.position = NewTextPos[2 + (ImageIndex[i] - i)*6]; v3.position = NewTextPos[4 + (ImageIndex[i] - i)*6]; ImageVertex[0 + i*4] = v0; ImageVertex[1 + i*4] = v1; ImageVertex[2 + i*4] = v2; ImageVertex[3 + i*4] = v3; NewTextPos.RemoveAt(0 + (ImageIndex[i] - i)*6); NewTextPos.RemoveAt(0 + (ImageIndex[i] - i)*6); NewTextPos.RemoveAt(0 + (ImageIndex[i] - i)*6); NewTextPos.RemoveAt(0 + (ImageIndex[i] - i)*6); NewTextPos.RemoveAt(0 + (ImageIndex[i] - i)*6); NewTextPos.RemoveAt(0 + (ImageIndex[i] - i)*6); NewTextIndex.RemoveAt(ImageIndex[i] - i); } for (int i = 0; i < NewTextIndex.Count; i++) { int index0 = 0 + NewTextIndex[i]*6; int index1 = 1 + NewTextIndex[i]*6; int index2 = 2 + NewTextIndex[i]*6; int index3 = 4 + NewTextIndex[i]*6; UIVertex v0 = TextVertex[index0]; UIVertex v1 = TextVertex[index1]; UIVertex v2 = TextVertex[index2]; UIVertex v3 = TextVertex[index3]; v0.position = NewTextPos[0 + i*6]; v1.position = NewTextPos[1 + i*6]; v2.position = NewTextPos[2 + i*6]; v3.position = NewTextPos[4 + i*6]; toFill.SetUIVertex(v0, 0 + NewTextIndex[i]*4); toFill.SetUIVertex(v1, 1 + NewTextIndex[i]*4); toFill.SetUIVertex(v2, 2 + NewTextIndex[i]*4); toFill.SetUIVertex(v3, 3 + NewTextIndex[i]*4); } ImagePlus.UpdateStatus(true, new VertexHelper(), ImageVertex); } else { ImagePlus.UpdateStatus(false, new VertexHelper(), null); } } protected void Initialize() { LineHeight = preferredHeight/cachedTextGenerator.lineCount; LineHeight = Mathf.Min(LineHeight, MaxLineHeight); //Debug.Log(transform.name + " " + LineHeight); ImageIndex = new List(); RemovePos = new List(); RemoveIndex = new List(); NewTextIndex = new List(); NewTextPos = new List(); ImageVertex = new List(); ToFill.GetUIVertexStream(TextVertex); for (int i = 0; i < text.Length; i++) { NewTextIndex.Add(i); } for (int i = 0; i < TextVertex.Count; i++) { NewTextPos.Add(TextVertex[i].position); } } protected void Move(int index1, int index2, float x, float y) { Vector3 offset = new Vector3(x, y, 0); for (int i = index1; i <= index2; i++) { NewTextPos[0 + i * 6] += offset; NewTextPos[1 + i * 6] += offset; NewTextPos[2 + i * 6] += offset; NewTextPos[3 + i * 6] += offset; NewTextPos[4 + i * 6] += offset; NewTextPos[5 + i * 6] += offset; } } protected void Retract() { StringBuilder sb = new StringBuilder(); for (int i = 0; i < NewTextIndex.Count; i++) { sb.Append(text[NewTextIndex[i]]); } string newText = sb.ToString(); List endIndex = new List(); List startIndex = new List(); List> imageGroup = new List>(); imageGroup.Add(new List()); startIndex.Add(0); for (int i = 0; i < newText.Length; i++) { if (newText[i] == '\n') { endIndex.Add(i); startIndex.Add(i + 1); imageGroup.Add(new List()); } else if (newText[i] == '<') { ImageIndex.Add(i); } } endIndex.Add(-1); for (int i = 0; i < ImageIndex.Count; i++) { bool recycle = false; for (int j = 0; j < endIndex.Count; j++) { if (ImageIndex[i] < endIndex[j]) { imageGroup[j].Add(ImageIndex[i]); recycle = true; break; } } if (recycle) { continue; } imageGroup.Back(0).Add(ImageIndex[i]); } for (int i = 0; i < imageGroup.Count; i++) { RetractLine(endIndex[i], imageGroup[i]); } float offset; if (alignment == TextAnchor.LowerCenter || alignment == TextAnchor.MiddleCenter || alignment == TextAnchor.UpperCenter) { for (int i = 0; i < startIndex.Count; i++) { if (i == startIndex.Count - 1) { offset = -GetWidth(startIndex[i], newText.Length - 1)/2; offset -= NewTextPos[0 + startIndex[i] * 6].x; Move(startIndex[i], newText.Length - 1, offset, 0); } else { offset = -GetWidth(startIndex[i], endIndex[i]-1)/2; offset -= NewTextPos[0 + startIndex[i]*6].x; Move(startIndex[i], endIndex[i]-1, offset, 0); } } } else if (alignment == TextAnchor.LowerRight || alignment == TextAnchor.MiddleRight || alignment == TextAnchor.UpperRight) { for (int i = 0; i < startIndex.Count; i++) { if (i == startIndex.Count - 1) { offset = cachedTextGenerator.rectExtents.xMax / 2 - NewTextPos[1 + (newText.Length - 1) * 6].x; Move(startIndex[i], newText.Length - 1, offset, 0); } else { offset = cachedTextGenerator.rectExtents.xMax/2 - NewTextPos[1 + (endIndex[i] - 1)*6].x; Move(startIndex[i], endIndex[i] - 1, offset, 0); } } } else if (alignment == TextAnchor.LowerLeft || alignment == TextAnchor.MiddleLeft || alignment == TextAnchor.UpperLeft) { } if (alignment == TextAnchor.LowerCenter || alignment == TextAnchor.LowerLeft || alignment == TextAnchor.LowerRight) { } else if (alignment == TextAnchor.MiddleCenter || alignment == TextAnchor.MiddleLeft || alignment == TextAnchor.MiddleRight) { } else if (alignment == TextAnchor.UpperCenter || alignment == TextAnchor.UpperLeft || alignment == TextAnchor.UpperRight) { } } protected void RetractLine(int endIndex, List imageIndex) { if (imageIndex.Count == 0) { return; } int rear; int front; if (imageIndex.Count == 1) { rear = endIndex - 1; front = imageIndex[0] + 1; if (endIndex == -1) { rear = NewTextIndex.Count - 1; } if (rear < front) { return; } Move(front, rear, -GetSpan(imageIndex[0], front), 0); } else { for (int i = 0; i < imageIndex.Count; i++) { if (endIndex == -1) { rear = NewTextIndex.Count - 1; } else { rear = endIndex - 1; } front = imageIndex.Back(i) + 1; if (rear < front) { continue; } Move(front, rear, -GetSpan(imageIndex.Back(i), front), 0); } } } protected void ClearChar(int index) { UIVertex v0 = TextVertex[0 + index*6]; UIVertex v1 = TextVertex[1 + index*6]; UIVertex v2 = TextVertex[2 + index*6]; UIVertex v3 = TextVertex[4 + index*6]; v0.uv0 = new Vector2(); v1.uv0 = new Vector2(); v2.uv0 = new Vector2(); v3.uv0 = new Vector2(); ToFill.SetUIVertex(v0, 0 + index * 4); ToFill.SetUIVertex(v1, 1 + index * 4); ToFill.SetUIVertex(v2, 2 + index * 4); ToFill.SetUIVertex(v3, 3 + index * 4); } protected void RemoveChar(ImageInfo imageInfo) { for (int i = imageInfo.Left + 1; i <= imageInfo.Right; i++) { RemoveIndex.Add(i); RemovePos.Add(0 + i*6); RemovePos.Add(1 + i*6); RemovePos.Add(2 + i*6); RemovePos.Add(3 + i*6); RemovePos.Add(4 + i*6); RemovePos.Add(5 + i*6); } } protected void CreateImage(ImageInfo imageInfo) { float height = LineHeight; float width = (height / imageInfo.SpriteInfo.Height) * imageInfo.SpriteInfo.Width; bool first = false; if (imageInfo.Left == 0) { first = true; } else if (!SameLine(imageInfo.Left-1, imageInfo.Left)) { first = true; } UIVertex v0 = new UIVertex(); UIVertex v1 = new UIVertex(); UIVertex v2 = new UIVertex(); UIVertex v3 = new UIVertex(); v0.color = Color.white; v1.color = Color.white; v2.color = Color.white; v3.color = Color.white; v0.uv0 = imageInfo.SpriteInfo.UvList[0]; v1.uv0 = imageInfo.SpriteInfo.UvList[1]; v2.uv0 = imageInfo.SpriteInfo.UvList[2]; v3.uv0 = imageInfo.SpriteInfo.UvList[3]; if (first) { Vector3 middleLeft = (TextVertex[0 + imageInfo.Left*6].position + TextVertex[4 + imageInfo.Left*6].position)/2; v0.position = middleLeft + new Vector3(0, height/2); v1.position = middleLeft + new Vector3(width, height / 2); v2.position = middleLeft + new Vector3(width, -height / 2); v3.position = middleLeft + new Vector3(0, -height / 2); ImageVertex.Add(v0); ImageVertex.Add(v1); ImageVertex.Add(v2); ImageVertex.Add(v3); } else { Vector3 middleRight = (TextVertex[1 + (imageInfo.Left - 1) * 6].position + TextVertex[2 + (imageInfo.Left - 1) * 6].position) / 2; if (SetY) { middleRight.y = Y; } v0.position = middleRight + new Vector3(0, height / 2); v1.position = middleRight + new Vector3(width, height / 2); v2.position = middleRight + new Vector3(width, -height / 2); v3.position = middleRight + new Vector3(0, -height / 2); ImageVertex.Add(v0); ImageVertex.Add(v1); ImageVertex.Add(v2); ImageVertex.Add(v3); } NewTextPos[0 + imageInfo.Left*6] = v0.position; NewTextPos[1 + imageInfo.Left*6] = v1.position; NewTextPos[2 + imageInfo.Left*6] = v2.position; NewTextPos[3 + imageInfo.Left*6] = v2.position; NewTextPos[4 + imageInfo.Left*6] = v3.position; NewTextPos[5 + imageInfo.Left*6] = v0.position; } protected bool SameLine(int index1, int index2) { //if (text[index1] == '\n' || text[index2] == '\n') //{ // return false; //} if (Mathf.Abs(GetCenter(index1).y - GetCenter(index2).y) < LineHeight/4) { return true; } else { return false; } } protected float GetSpan(int index1, int index2) { return (NewTextPos[0 + index2*6].x - NewTextPos[1 + index1*6].x); } protected float GetWidth(int index1, int index2) { return (NewTextPos[1 + index2 * 6].x - NewTextPos[0 + index1 * 6].x); } protected float GetHeight(int index1, int index2) { return (NewTextPos[0 + index1 * 6].y - NewTextPos[2 + index2 * 6].y); } protected Vector3 GetCenter(int index) { return (TextVertex[0 + index*6].position + TextVertex[3 + index*6].position)/2; } protected List GetImageList() { List imageList = new List(); ImageInfo imageInfo = new ImageInfo(); for (int i = 0; i < text.Length; i++) { if (text[i] == '<') { if (i + 1 != text.Length) { if (text[i + 1] == '(') { imageInfo = new ImageInfo(); imageInfo.Left = i; } } } else if (text[i] == ')') { if (i + 1 != text.Length) { if (text[i + 1] == '>') { imageInfo.Right = i + 1; string imageName = text.Between(imageInfo.Left + 2, imageInfo.Right - 2); if (SpriteAsset.SpriteInfoDic.TryGetValue(imageName, out imageInfo.SpriteInfo)) { imageList.Add(imageInfo); } } } } } return imageList; } }