Line.cs 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333
  1. using System.Collections.Generic;
  2. using UnityEngine;
  3. using UnityEngine.UI;
  4. namespace LineUI
  5. {
  6. [RequireComponent(typeof(CanvasRenderer))]
  7. [RequireComponent(typeof(RectTransform))]
  8. public class Line : Graphic
  9. {
  10. [SerializeField] private bool loop = false;
  11. [SerializeField] private float thickness = 1f;
  12. [SerializeField] private int roundCount = 0;
  13. [SerializeField] private Vector2 quadrilateralSize = new Vector2(100, 100);
  14. [SerializeField] private Color quadColor = Color.red;
  15. [SerializeField] private List<Vector2> screenPositions = new List<Vector2>();
  16. //获取当前的points
  17. [HideInInspector]
  18. public List<Vector2> ScreenPositions => screenPositions;
  19. [SerializeField] private Color maskColor = Color.red;
  20. //是否绘制内四边形
  21. [SerializeField] bool bDrawQuad = true;
  22. //是否绘制外围蒙板
  23. [SerializeField] bool bDrawMask = false;
  24. //[SerializeField] private Color quadTextColor = Color.black;
  25. //[SerializeField] private int quadFontSize = 14;
  26. //private List<Vector2> quadsToDraw = new List<Vector2>();
  27. //private List<string> quadTextToDraw = new List<string>();
  28. //private List<GameObject> quadObjects = new List<GameObject>();
  29. //private Stack<GameObject> objectPool = new Stack<GameObject>();
  30. private const int ObjectPoolLimit = 4;
  31. public RectTransform RectTr => rectTransform;
  32. public float MyThickness
  33. {
  34. get => thickness;
  35. set
  36. {
  37. if (value >= 10)
  38. {
  39. thickness = value;
  40. }
  41. }
  42. }
  43. public void SetLine(List<Vector2> screenPositions)
  44. {
  45. this.screenPositions = screenPositions;
  46. SetVerticesDirty();
  47. }
  48. public void SetDrawQuad(bool value) {
  49. bDrawQuad = value;
  50. SetVerticesDirty();
  51. }
  52. public void SetDrawMask(bool value)
  53. {
  54. bDrawMask = value;
  55. SetVerticesDirty();
  56. }
  57. protected override void OnPopulateMesh(VertexHelper vh)
  58. {
  59. vh.Clear();
  60. //quadsToDraw.Clear();
  61. //quadTextToDraw.Clear();
  62. if (screenPositions.Count < 2)
  63. return;
  64. SetLineVertices(vh);
  65. SetLineTriangles(vh);
  66. if(bDrawQuad) SetQuadrilateralVertices(vh);
  67. if(bDrawMask) DrawMask(vh); // 绘制蒙版
  68. }
  69. private void SetLineVertices(VertexHelper vh)
  70. {
  71. UIVertex vert = UIVertex.simpleVert;
  72. vert.color = color;
  73. List<Vector2> _screenPositions = new List<Vector2>(screenPositions);
  74. if (loop)
  75. {
  76. _screenPositions.Add(screenPositions[0]);
  77. _screenPositions.Add(screenPositions[1]);
  78. }
  79. float lastAngle = 0;
  80. for (int i = 1; i < _screenPositions.Count; i++)
  81. {
  82. Vector2 previousPos = _screenPositions[i - 1];
  83. Vector2 currentPos = _screenPositions[i];
  84. Vector2 dif = currentPos - previousPos;
  85. float angle = Vector2.SignedAngle(Vector2.right, dif);
  86. Vector2 offset = Quaternion.Euler(0, 0, angle) * Vector3.up * thickness;
  87. if (i > 1)
  88. {
  89. float anglePerRound = (angle - lastAngle) / roundCount;
  90. for (int j = 0; j <= roundCount; j++)
  91. {
  92. float ang = lastAngle + anglePerRound * j;
  93. Vector2 roundOffset = Quaternion.Euler(0, 0, ang) * Vector2.up * thickness;
  94. vert.position = previousPos - roundOffset;
  95. vh.AddVert(vert);
  96. vert.position = previousPos + roundOffset;
  97. vh.AddVert(vert);
  98. }
  99. }
  100. lastAngle = angle;
  101. vert.position = previousPos - offset;
  102. vh.AddVert(vert);
  103. vert.position = previousPos + offset;
  104. vh.AddVert(vert);
  105. vert.position = currentPos - offset;
  106. vh.AddVert(vert);
  107. vert.position = currentPos + offset;
  108. vh.AddVert(vert);
  109. }
  110. }
  111. private void SetQuadrilateralVertices(VertexHelper vh)
  112. {
  113. UIVertex vert = UIVertex.simpleVert;
  114. vert.color = quadColor;
  115. List<Vector2> _screenPositions = new List<Vector2>(screenPositions);
  116. if (loop)
  117. {
  118. _screenPositions.Add(screenPositions[0]);
  119. _screenPositions.Add(screenPositions[1]);
  120. }
  121. for (int i = 1; i < _screenPositions.Count; i++)
  122. {
  123. Vector2 previousPos = _screenPositions[i - 1];
  124. Vector2 currentPos = _screenPositions[i];
  125. if (i > 1)
  126. {
  127. Vector2 prevDir = (_screenPositions[i - 1] - _screenPositions[i - 2]).normalized;
  128. Vector2 currentDir = (currentPos - previousPos).normalized;
  129. int index = i == 4 ? 4 : i % 4;
  130. if (index == 4 || index == 2)
  131. {
  132. DrawSquareAtCorner(vh, previousPos, prevDir, currentDir, quadrilateralSize.x, quadrilateralSize.y, index);
  133. }
  134. else {
  135. DrawSquareAtCorner(vh, previousPos, prevDir, currentDir, quadrilateralSize.y, quadrilateralSize.x, index);
  136. }
  137. }
  138. }
  139. }
  140. private void DrawSquareAtCorner(VertexHelper vh, Vector2 corner, Vector2 prevDir, Vector2 currentDir, float width, float height, int index)
  141. {
  142. UIVertex vert = UIVertex.simpleVert;
  143. vert.color = quadColor;
  144. Vector2[] corners = new Vector2[4];
  145. corners[0] = corner;
  146. corners[1] = corner + prevDir * -width;
  147. corners[2] = corner + prevDir * -width + currentDir * height;
  148. corners[3] = corner + currentDir * height;
  149. foreach (Vector2 pos in corners)
  150. {
  151. vert.position = pos;
  152. vh.AddVert(vert);
  153. }
  154. int startIndex = vh.currentVertCount - 4;
  155. vh.AddTriangle(startIndex, startIndex + 1, startIndex + 2);
  156. vh.AddTriangle(startIndex + 2, startIndex + 3, startIndex);
  157. // Store the quad's center position and text for later use
  158. //Vector2 quadCenter = corner + (prevDir * -width + currentDir * height) / 2;
  159. //quadsToDraw.Add(quadCenter);
  160. //quadTextToDraw.Add(index.ToString());
  161. }
  162. private void SetLineTriangles(VertexHelper vh)
  163. {
  164. for (int i = 0; i < vh.currentVertCount - 2; i += 2)
  165. {
  166. int index = i;
  167. vh.AddTriangle(index, index + 1, index + 3);
  168. vh.AddTriangle(index + 3, index + 2, index);
  169. }
  170. }
  171. private void DrawMask(VertexHelper vh)
  172. {
  173. UIVertex vert = UIVertex.simpleVert;
  174. vert.color = maskColor;
  175. //// 屏幕四个角的坐标
  176. //Vector2[] screenCorners = new Vector2[]
  177. //{
  178. // new Vector2(-Screen.width / 2, -Screen.height / 2), // 左下角
  179. // new Vector2(Screen.width / 2, -Screen.height / 2), // 右下角
  180. // new Vector2(Screen.width / 2, Screen.height / 2), // 右上角
  181. // new Vector2(-Screen.width / 2, Screen.height / 2), // 左上角
  182. //};
  183. // 获取 RectTransform 的实际四个角坐标
  184. Rect rect = rectTransform.rect;
  185. Vector2[] screenCorners = new Vector2[]
  186. {
  187. new Vector2(rect.xMin, rect.yMin), // 左下角
  188. new Vector2(rect.xMax, rect.yMin), // 右下角
  189. new Vector2(rect.xMax, rect.yMax), // 右上角
  190. new Vector2(rect.xMin, rect.yMax), // 左上角
  191. };
  192. // 添加四个点作为内框(中间区域的四个顶点)
  193. Vector2[] innerCorners = screenPositions.ToArray();
  194. // 分别绘制四个蒙版区域
  195. // 1. 左上区域:围绕左上角和内框左上、右上
  196. AddQuad(vh, screenCorners[3], innerCorners[3], innerCorners[2], screenCorners[2]);
  197. // 2. 右上区域:围绕右上角和内框右上、右下
  198. AddQuad(vh, innerCorners[2], screenCorners[2], screenCorners[1], innerCorners[1]);
  199. // 3. 右下区域:围绕右下角和内框右下、左下
  200. AddQuad(vh, innerCorners[0], innerCorners[1], screenCorners[1], screenCorners[0]);
  201. // 4. 左下区域:围绕左下角和内框左下、左上
  202. AddQuad(vh, screenCorners[3], screenCorners[0], innerCorners[0], innerCorners[3]);
  203. }
  204. private void AddQuad(VertexHelper vh, Vector2 corner1, Vector2 corner2, Vector2 corner3, Vector2 corner4)
  205. {
  206. UIVertex vert = UIVertex.simpleVert;
  207. vert.color = maskColor;
  208. vert.position = corner1;
  209. vh.AddVert(vert);
  210. vert.position = corner2;
  211. vh.AddVert(vert);
  212. vert.position = corner3;
  213. vh.AddVert(vert);
  214. vert.position = corner4;
  215. vh.AddVert(vert);
  216. Debug.Log("vh.currentVertCount:"+ vh.currentVertCount);
  217. int startIndex = vh.currentVertCount - 4;
  218. vh.AddTriangle(startIndex, startIndex + 1, startIndex + 2);
  219. vh.AddTriangle(startIndex + 2, startIndex + 3, startIndex);
  220. }
  221. //private void LateUpdate()
  222. //{
  223. // foreach (var quadObj in quadObjects)
  224. // {
  225. // if (quadObj != null)
  226. // {
  227. // objectPool.Push(quadObj);
  228. // }
  229. // }
  230. // quadObjects.Clear();
  231. // for (int i = 0; i < quadsToDraw.Count; i++)
  232. // {
  233. // GameObject quadGO = GetQuadObject();
  234. // if (quadGO != null)
  235. // {
  236. // quadGO.SetActive(true);
  237. // quadGO.GetComponent<RectTransform>().anchoredPosition = quadsToDraw[i];
  238. // Text quadTextComponent = quadGO.GetComponent<Text>();
  239. // quadTextComponent.text = quadTextToDraw[i];
  240. // quadTextComponent.fontSize = quadFontSize;
  241. // quadTextComponent.color = quadTextColor;
  242. // quadTextComponent.alignment = TextAnchor.MiddleCenter;
  243. // }
  244. // }
  245. // quadsToDraw.Clear();
  246. // quadTextToDraw.Clear();
  247. //}
  248. //private GameObject GetQuadObject()
  249. //{
  250. // if (objectPool.Count > 0)
  251. // {
  252. // GameObject quadGO = objectPool.Pop();
  253. // if (quadGO != null)
  254. // {
  255. // quadObjects.Add(quadGO);
  256. // return quadGO;
  257. // }
  258. // }
  259. // if (quadObjects.Count < ObjectPoolLimit)
  260. // {
  261. // GameObject newQuadGO = new GameObject("QuadText", typeof(RectTransform), typeof(Text));
  262. // newQuadGO.transform.SetParent(this.transform);
  263. // Text quadTextComponent = newQuadGO.GetComponent<Text>();
  264. // quadTextComponent.alignment = TextAnchor.MiddleCenter;
  265. // quadTextComponent.rectTransform.sizeDelta = new Vector2(quadrilateralSize.x, quadrilateralSize.y);
  266. // quadObjects.Add(newQuadGO);
  267. // return newQuadGO;
  268. // }
  269. // return null;
  270. //}
  271. }
  272. }