using System.Collections.Generic; using UnityEngine; using UnityEngine.UI; namespace LineUI { [RequireComponent(typeof(CanvasRenderer))] [RequireComponent(typeof(RectTransform))] public class Line : Graphic { [SerializeField] private bool loop = false; [SerializeField] private float thickness = 1f; [SerializeField] private int roundCount = 0; [SerializeField] private Vector2 quadrilateralSize = new Vector2(100, 100); [SerializeField] private Color quadColor = Color.red; [SerializeField] private List screenPositions = new List(); [SerializeField] private Color maskColor = Color.red; //是否绘制内四边形 [SerializeField] bool bDrawQuad = true; //是否绘制外围蒙板 [SerializeField] bool bDrawMask = false; //[SerializeField] private Color quadTextColor = Color.black; //[SerializeField] private int quadFontSize = 14; //private List quadsToDraw = new List(); //private List quadTextToDraw = new List(); //private List quadObjects = new List(); //private Stack objectPool = new Stack(); private const int ObjectPoolLimit = 4; public RectTransform RectTr => rectTransform; public float MyThickness { get => thickness; set { if (value >= 10) { thickness = value; } } } public void SetLine(List screenPositions) { this.screenPositions = screenPositions; SetVerticesDirty(); } public void SetDrawQuad(bool value) { bDrawQuad = value; } public void SetDrawMask(bool value) { bDrawMask = value; } protected override void OnPopulateMesh(VertexHelper vh) { vh.Clear(); //quadsToDraw.Clear(); //quadTextToDraw.Clear(); if (screenPositions.Count < 2) return; SetLineVertices(vh); SetLineTriangles(vh); if(bDrawQuad) SetQuadrilateralVertices(vh); if(bDrawMask) DrawMask(vh); // 绘制蒙版 } private void SetLineVertices(VertexHelper vh) { UIVertex vert = UIVertex.simpleVert; vert.color = color; List _screenPositions = new List(screenPositions); if (loop) { _screenPositions.Add(screenPositions[0]); _screenPositions.Add(screenPositions[1]); } float lastAngle = 0; for (int i = 1; i < _screenPositions.Count; i++) { Vector2 previousPos = _screenPositions[i - 1]; Vector2 currentPos = _screenPositions[i]; Vector2 dif = currentPos - previousPos; float angle = Vector2.SignedAngle(Vector2.right, dif); Vector2 offset = Quaternion.Euler(0, 0, angle) * Vector3.up * thickness; if (i > 1) { float anglePerRound = (angle - lastAngle) / roundCount; for (int j = 0; j <= roundCount; j++) { float ang = lastAngle + anglePerRound * j; Vector2 roundOffset = Quaternion.Euler(0, 0, ang) * Vector2.up * thickness; vert.position = previousPos - roundOffset; vh.AddVert(vert); vert.position = previousPos + roundOffset; vh.AddVert(vert); } } lastAngle = angle; vert.position = previousPos - offset; vh.AddVert(vert); vert.position = previousPos + offset; vh.AddVert(vert); vert.position = currentPos - offset; vh.AddVert(vert); vert.position = currentPos + offset; vh.AddVert(vert); } } private void SetQuadrilateralVertices(VertexHelper vh) { UIVertex vert = UIVertex.simpleVert; vert.color = quadColor; List _screenPositions = new List(screenPositions); if (loop) { _screenPositions.Add(screenPositions[0]); _screenPositions.Add(screenPositions[1]); } for (int i = 1; i < _screenPositions.Count; i++) { Vector2 previousPos = _screenPositions[i - 1]; Vector2 currentPos = _screenPositions[i]; if (i > 1) { Vector2 prevDir = (_screenPositions[i - 1] - _screenPositions[i - 2]).normalized; Vector2 currentDir = (currentPos - previousPos).normalized; int index = i == 4 ? 4 : i % 4; if (index == 4 || index == 2) { DrawSquareAtCorner(vh, previousPos, prevDir, currentDir, quadrilateralSize.x, quadrilateralSize.y, index); } else { DrawSquareAtCorner(vh, previousPos, prevDir, currentDir, quadrilateralSize.y, quadrilateralSize.x, index); } } } } private void DrawSquareAtCorner(VertexHelper vh, Vector2 corner, Vector2 prevDir, Vector2 currentDir, float width, float height, int index) { UIVertex vert = UIVertex.simpleVert; vert.color = quadColor; Vector2[] corners = new Vector2[4]; corners[0] = corner; corners[1] = corner + prevDir * -width; corners[2] = corner + prevDir * -width + currentDir * height; corners[3] = corner + currentDir * height; foreach (Vector2 pos in corners) { vert.position = pos; vh.AddVert(vert); } int startIndex = vh.currentVertCount - 4; vh.AddTriangle(startIndex, startIndex + 1, startIndex + 2); vh.AddTriangle(startIndex + 2, startIndex + 3, startIndex); // Store the quad's center position and text for later use //Vector2 quadCenter = corner + (prevDir * -width + currentDir * height) / 2; //quadsToDraw.Add(quadCenter); //quadTextToDraw.Add(index.ToString()); } private void SetLineTriangles(VertexHelper vh) { for (int i = 0; i < vh.currentVertCount - 2; i += 2) { int index = i; vh.AddTriangle(index, index + 1, index + 3); vh.AddTriangle(index + 3, index + 2, index); } } private void DrawMask(VertexHelper vh) { UIVertex vert = UIVertex.simpleVert; vert.color = maskColor; //// 屏幕四个角的坐标 //Vector2[] screenCorners = new Vector2[] //{ // new Vector2(-Screen.width / 2, -Screen.height / 2), // 左下角 // new Vector2(Screen.width / 2, -Screen.height / 2), // 右下角 // new Vector2(Screen.width / 2, Screen.height / 2), // 右上角 // new Vector2(-Screen.width / 2, Screen.height / 2), // 左上角 //}; // 获取 RectTransform 的实际四个角坐标 Rect rect = rectTransform.rect; Vector2[] screenCorners = new Vector2[] { new Vector2(rect.xMin, rect.yMin), // 左下角 new Vector2(rect.xMax, rect.yMin), // 右下角 new Vector2(rect.xMax, rect.yMax), // 右上角 new Vector2(rect.xMin, rect.yMax), // 左上角 }; // 添加四个点作为内框(中间区域的四个顶点) Vector2[] innerCorners = screenPositions.ToArray(); // 分别绘制四个蒙版区域 // 1. 左上区域:围绕左上角和内框左上、右上 AddQuad(vh, screenCorners[3], innerCorners[3], innerCorners[2], screenCorners[2]); // 2. 右上区域:围绕右上角和内框右上、右下 AddQuad(vh, innerCorners[2], screenCorners[2], screenCorners[1], innerCorners[1]); // 3. 右下区域:围绕右下角和内框右下、左下 AddQuad(vh, innerCorners[0], innerCorners[1], screenCorners[1], screenCorners[0]); // 4. 左下区域:围绕左下角和内框左下、左上 AddQuad(vh, screenCorners[3], screenCorners[0], innerCorners[0], innerCorners[3]); } private void AddQuad(VertexHelper vh, Vector2 corner1, Vector2 corner2, Vector2 corner3, Vector2 corner4) { UIVertex vert = UIVertex.simpleVert; vert.color = maskColor; vert.position = corner1; vh.AddVert(vert); vert.position = corner2; vh.AddVert(vert); vert.position = corner3; vh.AddVert(vert); vert.position = corner4; vh.AddVert(vert); Debug.Log("vh.currentVertCount:"+ vh.currentVertCount); int startIndex = vh.currentVertCount - 4; vh.AddTriangle(startIndex, startIndex + 1, startIndex + 2); vh.AddTriangle(startIndex + 2, startIndex + 3, startIndex); } //private void LateUpdate() //{ // foreach (var quadObj in quadObjects) // { // if (quadObj != null) // { // objectPool.Push(quadObj); // } // } // quadObjects.Clear(); // for (int i = 0; i < quadsToDraw.Count; i++) // { // GameObject quadGO = GetQuadObject(); // if (quadGO != null) // { // quadGO.SetActive(true); // quadGO.GetComponent().anchoredPosition = quadsToDraw[i]; // Text quadTextComponent = quadGO.GetComponent(); // quadTextComponent.text = quadTextToDraw[i]; // quadTextComponent.fontSize = quadFontSize; // quadTextComponent.color = quadTextColor; // quadTextComponent.alignment = TextAnchor.MiddleCenter; // } // } // quadsToDraw.Clear(); // quadTextToDraw.Clear(); //} //private GameObject GetQuadObject() //{ // if (objectPool.Count > 0) // { // GameObject quadGO = objectPool.Pop(); // if (quadGO != null) // { // quadObjects.Add(quadGO); // return quadGO; // } // } // if (quadObjects.Count < ObjectPoolLimit) // { // GameObject newQuadGO = new GameObject("QuadText", typeof(RectTransform), typeof(Text)); // newQuadGO.transform.SetParent(this.transform); // Text quadTextComponent = newQuadGO.GetComponent(); // quadTextComponent.alignment = TextAnchor.MiddleCenter; // quadTextComponent.rectTransform.sizeDelta = new Vector2(quadrilateralSize.x, quadrilateralSize.y); // quadObjects.Add(newQuadGO); // return newQuadGO; // } // return null; //} } }