当前位置:   article > 正文

Unity UGUI 效果 之 UI 元素 多边形UI (例如雷达图,圆形,不规则多边形 UI等)显示 的简单实现的几种方法整理_unity ui不规则画面

unity ui不规则画面

Unity UGUI 效果 之 UI 元素 多边形UI (例如雷达图,圆形,不规则多边形 UI等)显示 的简单实现的几种方法整理

 

目录

Unity UGUI 效果 之 UI 元素 多边形UI (例如雷达图,圆形,不规则多边形 UI等)显示 的简单实现的几种方法整理

一、简单介绍

二、可以自由调整形状的多边形 UI

1、功能说明

3、效果预览

3、 实现步骤

4、关键代码

三、调整对应边数,实现任意正多边形,甚至圆形 UI

1、功能介绍

2、效果预览

3、实现步骤

4、关键代码

四、类雷达图的多边形 UI

1、功能说明

2、效果预览

3、实现步骤

4、关键代码

五、类雷达图多边形UI(二)

1、功能介绍

2、效果预览

3、实现步骤

4、关键代码

六、雷达图 UGUI 案例

1、效果图

2、Unity 场景布局

3、关键代码


 

一、简单介绍

UGUI,是Unity自带的 GUI 系统,有别于 NGUI;使用 UGUI 也能制作出比较酷炫的效果 。

本节介绍,在 UGUI中 普通的 UI 元素中实现简单的多边形显示的若干方法的整理总结。

UGUI 的 UI 扩展,可参见 unity-ui-extensions 工程学习: https://bitbucket.org/ddreaper/unity-ui-extensions

接下来将逐一说明几种多边形UI的方法。

 

二、可以自由调整形状的多边形 UI

1、功能说明

1)添加脚本 PolygonUIMesh

2)在该脚本的组建下,添加子物体,作为 Polygon 多边形的点

3)任意移动子物体,Polygon 多边形都会穗子变化

 

3、效果预览

 

3、 实现步骤

1)编写好脚本 PolygonUIMesh

 

2)挂在 PolygonUIMesh 脚本到 Canvas 下的物体上

(注意:PolygonUIMesh 相当于 Button 的 Image,所以可以在其组建上添加 Button,实现按钮功能等)

 

3)在挂载 PolygonUIMesh 脚本组件下,添加子物体,会自动作为多变形的点,移动他们既可以跳帧多边形形状了

 

4、关键代码

  1. using UnityEngine;
  2. using System.Collections;
  3. using UnityEngine.UI;
  4. public class PolygonUIMesh : Graphic
  5. {
  6. private void OnGUI()
  7. {
  8. // 实时检测更新绘制 OnPopulateMesh 中 transform.child 位置
  9. SetAllDirty();
  10. }
  11. /// <summary>
  12. /// 根据 transform.child 位置 绘制 Mesh
  13. /// </summary>
  14. /// <param name="vh"></param>
  15. protected override void OnPopulateMesh(VertexHelper vh)
  16. {
  17. if (transform.childCount <= 2)
  18. {
  19. return;
  20. }
  21. Color32 color32 = color;
  22. vh.Clear();
  23. // 几何图形的顶点,本例中根据子节点坐标确定顶点
  24. foreach (Transform child in transform)
  25. {
  26. vh.AddVert(child.localPosition, color32, new Vector2(0f, 0f));
  27. }
  28. for (int i = 0; i < (transform.childCount-2); i ++)
  29. {
  30. // 几何图形中的三角形
  31. vh.AddTriangle(i+1, i + 2, 0);
  32. }
  33. }
  34. /// <summary>
  35. /// 点的辅助绘制
  36. /// </summary>
  37. private void OnDrawGizmos()
  38. {
  39. if (transform.childCount == 0)
  40. {
  41. return;
  42. }
  43. for (int i = 0; i < transform.childCount; i++)
  44. {
  45. Gizmos.DrawSphere(transform.GetChild(i).position, 2.55f);
  46. Gizmos.DrawIcon(transform.GetChild(i).position, "numbers/numbers_" + i+".PNG",false);
  47. }
  48. }
  49. }

 

三、调整对应边数,实现任意正多边形,甚至圆形 UI

1、功能介绍

1)这里是继承 RawImage,调整其多边形的绘制

2)改变边数,实现 UI 多边形

3)调整 UI 元素宽高,效果会有不一样(局限性)

 

2、效果预览

 

3、实现步骤

1)编写脚本 UIPolygonRawImage ,继承 RawImage ,重写其方法,实现多边形UI

(其中:UIPolygonRawImageInspector 脚本是对 UIPolygonRawImage  变量显示的调整,放在 Editor 目录下即可 )

(UIPolygonRawImageInspector  可以根据需要可要可不要,不影响功能)

 

2)在 Canvas 下添加组件,并挂载脚本 UIPolygonRawImage ,对应添加图片

(跟使用 RawImage差不多,只是多了个边数)

 

3)调整边数,实现多边形 UI

 

4、关键代码

参考博文:https://www.xuanyusong.com/archives/4375

1)UIPolygonRawImage

  1. using System.Collections;
  2. using System.Collections.Generic;
  3. using UnityEngine;
  4. using UnityEngine.UI;
  5. public class UIPolygonRawImage : RawImage
  6. {
  7. const int FILL_PERCENT = 100;
  8. float thickness = 5;
  9. [SerializeField]
  10. [Range(4, 360)]
  11. int _segments = 36;
  12. public int segments
  13. {
  14. get { return _segments; }
  15. set
  16. {
  17. if (_segments != value)
  18. {
  19. _segments = value;
  20. SetVerticesDirty();
  21. #if UNITY_EDITOR
  22. UnityEditor.EditorUtility.SetDirty(transform);
  23. #endif
  24. }
  25. }
  26. }
  27. protected override void OnRectTransformDimensionsChange()
  28. {
  29. base.OnRectTransformDimensionsChange();
  30. this.thickness = (float)Mathf.Clamp(this.thickness, 0, rectTransform.rect.width / 2);
  31. }
  32. protected override void OnPopulateMesh(VertexHelper vh)
  33. {
  34. float outer = -rectTransform.pivot.x * rectTransform.rect.width;
  35. float inner = -rectTransform.pivot.x * rectTransform.rect.width + this.thickness;
  36. vh.Clear();
  37. Vector2 prevX = Vector2.zero;
  38. Vector2 prevY = Vector2.zero;
  39. Vector2 uv0 = new Vector2(0, 0);
  40. Vector2 uv1 = new Vector2(0, 1);
  41. Vector2 uv2 = new Vector2(1, 1);
  42. Vector2 uv3 = new Vector2(1, 0);
  43. Vector2 pos0;
  44. Vector2 pos1;
  45. Vector2 pos2;
  46. Vector2 pos3;
  47. float tw = rectTransform.rect.width;
  48. float th = rectTransform.rect.height;
  49. float angleByStep = (FILL_PERCENT / 100f * (Mathf.PI * 2f)) / segments;
  50. float currentAngle = 0f;
  51. for (int i = 0; i < segments + 1; i++)
  52. {
  53. float c = Mathf.Cos(currentAngle);
  54. float s = Mathf.Sin(currentAngle);
  55. StepThroughPointsAndFill(outer, inner, ref prevX, ref prevY, out pos0, out pos1, out pos2, out pos3, c, s);
  56. uv0 = new Vector2(pos0.x / tw + 0.5f, pos0.y / th + 0.5f);
  57. uv1 = new Vector2(pos1.x / tw + 0.5f, pos1.y / th + 0.5f);
  58. uv2 = new Vector2(pos2.x / tw + 0.5f, pos2.y / th + 0.5f);
  59. uv3 = new Vector2(pos3.x / tw + 0.5f, pos3.y / th + 0.5f);
  60. vh.AddUIVertexQuad(SetVbo(new[] { pos0, pos1, pos2, pos3 }, new[] { uv0, uv1, uv2, uv3 }));
  61. currentAngle += angleByStep;
  62. }
  63. }
  64. private void StepThroughPointsAndFill(float outer, float inner, ref Vector2 prevX, ref Vector2 prevY, out Vector2 pos0, out Vector2 pos1, out Vector2 pos2, out Vector2 pos3, float c, float s)
  65. {
  66. pos0 = prevX;
  67. pos1 = new Vector2(outer * c, outer * s);
  68. pos2 = Vector2.zero;
  69. pos3 = Vector2.zero;
  70. prevX = pos1;
  71. prevY = pos2;
  72. }
  73. protected UIVertex[] SetVbo(Vector2[] vertices, Vector2[] uvs)
  74. {
  75. UIVertex[] vbo = new UIVertex[4];
  76. for (int i = 0; i < vertices.Length; i++)
  77. {
  78. var vert = UIVertex.simpleVert;
  79. vert.color = color;
  80. vert.position = vertices[i];
  81. vert.uv0 = uvs[i];
  82. vbo[i] = vert;
  83. }
  84. return vbo;
  85. }
  86. }

 

2)UIPolygonRawImageInspector

  1. using System.Collections;
  2. using System.Collections.Generic;
  3. using UnityEditor;
  4. using UnityEditor.UI;
  5. using UnityEngine;
  6. [CustomEditor(typeof(UIPolygonRawImage), true)]
  7. [CanEditMultipleObjects]
  8. public class UIPolygonRawImageInspector : RawImageEditor
  9. {
  10. public override void OnInspectorGUI()
  11. {
  12. base.OnInspectorGUI();
  13. UIPolygonRawImage polygon = target as UIPolygonRawImage;
  14. polygon.segments = Mathf.Clamp(EditorGUILayout.IntField("UICircle多边形", polygon.segments), 4, 360);
  15. }
  16. }

 

四、类雷达图的多边形 UI

1、功能说明

1)查看UGUI的代码可以得知,绘制ui图的方法其实是绘制mesh,然后对其进行填充。正常一个Image图片,绘制有四个顶点。为了实现多边形,继承于MaskableGraphic,重写OnPopulateMesh,重新绘制顶点。

2)能调整边数,点的比例,是否填充,旋转等,控制显示雷达图的样式

 

2、效果预览

 

3、实现步骤

1)编写脚本,实现类雷达图的功能

 

2)把脚本挂载到Canvas 的组建下

 

3)调整脚本参数,即可根据需要调整成自己想要的样式

 

4、关键代码

参考博文:https://blog.csdn.net/u013012420/article/details/105956884

  1. using UnityEngine;
  2. using UnityEngine.UI;
  3. /// <summary>
  4. /// 雷达图
  5. /// </summary>
  6. public class RadarMapUIMesh : MaskableGraphic
  7. {
  8. public bool fill = true;
  9. public float thickness = 5;
  10. [Range(3, 360)]
  11. public int sides = 3;
  12. [Range(0, 360)]
  13. public float rotation = 0;
  14. [Range(0, 1)]
  15. public float[] VerticesDistances = new float[3];
  16. private float size = 0;
  17. public void DrawPolygon(int _sides)
  18. {
  19. sides = _sides;
  20. VerticesDistances = new float[_sides + 1];
  21. for (int i = 0; i < _sides; i++) VerticesDistances[i] = 1; ;
  22. rotation = 0;
  23. }
  24. public void DrawPolygon(int _sides, float[] _VerticesDistances)
  25. {
  26. sides = _sides;
  27. VerticesDistances = _VerticesDistances;
  28. rotation = 0;
  29. }
  30. public void DrawPolygon(int _sides, float[] _VerticesDistances, float _rotation)
  31. {
  32. sides = _sides;
  33. VerticesDistances = _VerticesDistances;
  34. rotation = _rotation;
  35. }
  36. void Update()
  37. {
  38. size = rectTransform.rect.width;
  39. if (rectTransform.rect.width > rectTransform.rect.height)
  40. size = rectTransform.rect.height;
  41. else
  42. size = rectTransform.rect.width;
  43. thickness = (float)Mathf.Clamp(thickness, 0, size / 2);
  44. }
  45. protected override void OnPopulateMesh(VertexHelper vh)
  46. {
  47. vh.Clear();
  48. Vector2 prevX = Vector2.zero;
  49. Vector2 prevY = Vector2.zero;
  50. Vector2 uv0 = new Vector2(0, 0);
  51. Vector2 uv1 = new Vector2(0, 1);
  52. Vector2 uv2 = new Vector2(1, 1);
  53. Vector2 uv3 = new Vector2(1, 0);
  54. Vector2 pos0;
  55. Vector2 pos1;
  56. Vector2 pos2;
  57. Vector2 pos3;
  58. float degrees = 360f / sides;
  59. int vertices = sides + 1;
  60. if (VerticesDistances.Length != vertices)
  61. {
  62. VerticesDistances = new float[vertices];
  63. for (int i = 0; i < vertices - 1; i++) VerticesDistances[i] = 1;
  64. }
  65. // last vertex is also the first!
  66. VerticesDistances[vertices - 1] = VerticesDistances[0];
  67. for (int i = 0; i < vertices; i++)
  68. {
  69. float outer = -rectTransform.pivot.x * size * VerticesDistances[i];
  70. float inner = -rectTransform.pivot.x * size * VerticesDistances[i] + thickness;
  71. float rad = Mathf.Deg2Rad * (i * degrees + rotation);
  72. float c = Mathf.Cos(rad);
  73. float s = Mathf.Sin(rad);
  74. uv0 = new Vector2(0, 1);
  75. uv1 = new Vector2(1, 1);
  76. uv2 = new Vector2(1, 0);
  77. uv3 = new Vector2(0, 0);
  78. pos0 = prevX;
  79. pos1 = new Vector2(outer * c, outer * s);
  80. if (fill)
  81. {
  82. pos2 = Vector2.zero;
  83. pos3 = Vector2.zero;
  84. }
  85. else
  86. {
  87. pos2 = new Vector2(inner * c, inner * s);
  88. pos3 = prevY;
  89. }
  90. prevX = pos1;
  91. prevY = pos2;
  92. SetVbo(new[] { pos0, pos1, pos2, pos3 }, new[] { uv0, uv1, uv2, uv3 });
  93. vh.AddUIVertexQuad(vbo);
  94. }
  95. }
  96. private UIVertex[] vbo = new UIVertex[4];
  97. private void SetVbo(Vector2[] vertices, Vector2[] uvs)
  98. {
  99. for (int i = 0; i < vertices.Length; i++)
  100. {
  101. var vert = UIVertex.simpleVert;
  102. vert.color = color;
  103. vert.position = vertices[i];
  104. vert.uv0 = uvs[i];
  105. vbo[i] = vert;
  106. }
  107. }
  108. }

 

五、类雷达图多边形UI(二)

参考博文:http://www.lsngo.net/2017/10/26/unity_polygonalui/

1、功能介绍

1)可以添加图线

2)可以调整边数,和点的比例,改变样式

 

2、效果预览

 

3、实现步骤

1)编写脚本 PolygonImage 等,实现功能

(注意有些脚本最好放在Editor 文件夹下)

 

2)把脚本 挂载到 Canvas 下的组件上

 

3)根据需要调整效果如上

 

 

4、关键代码

1)PolygonImage

  1. using UnityEngine;
  2. using UnityEngine.UI;
  3. using System.Collections.Generic;
  4. public class PolygonImage : MaskableGraphic, ISerializationCallbackReceiver, ICanvasRaycastFilter
  5. {
  6. [SerializeField]
  7. Texture m_Texture;
  8. public PolygonImageEdge edgeWeights;
  9. public override Texture mainTexture
  10. {
  11. get
  12. {
  13. if (m_Texture == null)
  14. {
  15. if (material != null && material.mainTexture != null)
  16. {
  17. return material.mainTexture;
  18. }
  19. return s_WhiteTexture;
  20. }
  21. return m_Texture;
  22. }
  23. }
  24. /// <summary>
  25. /// Texture to be used.
  26. /// </summary>
  27. public Texture texture
  28. {
  29. get
  30. {
  31. return m_Texture;
  32. }
  33. set
  34. {
  35. if (m_Texture == value)
  36. return;
  37. m_Texture = value;
  38. SetVerticesDirty();
  39. SetMaterialDirty();
  40. }
  41. }
  42. public bool IsRaycastLocationValid(Vector2 sp, Camera eventCamera)
  43. {
  44. if (raycastTarget)
  45. {
  46. Vector2 local;
  47. RectTransformUtility.ScreenPointToLocalPointInRectangle(rectTransform, sp, eventCamera, out local);
  48. int edgeCount = edgeWeights.EdgeCount;
  49. float deltaAngle = 360f/edgeCount;
  50. for (int i = 0; i < edgeCount; i++)
  51. {
  52. bool result = IsInPolygon(i, deltaAngle, local);
  53. if (result)
  54. return true;
  55. }
  56. }
  57. return false;
  58. }
  59. public virtual void OnAfterDeserialize()
  60. {
  61. }
  62. public virtual void OnBeforeSerialize()
  63. {
  64. }
  65. protected override void OnPopulateMesh(VertexHelper vh)
  66. {
  67. if (edgeWeights == null || edgeWeights.EdgeCount <= 2)
  68. {
  69. base.OnPopulateMesh(vh);
  70. return;
  71. }
  72. int edgeCount = edgeWeights.EdgeCount;
  73. float deltaAngle = 360f/edgeCount;
  74. vh.Clear();
  75. for (int i = 0; i < edgeCount; i++)
  76. {
  77. GetTriangle(vh, i, deltaAngle);
  78. }
  79. }
  80. private void GetTriangle(VertexHelper vh, int index, float deltaAngle)
  81. {
  82. float edgeLength = Mathf.Min(rectTransform.rect.width, rectTransform.rect.height)*0.5f;
  83. var color32 = color;
  84. Vector3 cent = new Vector3(0, 0);
  85. float angle1 = 90+(index + 1)*deltaAngle;
  86. float angle2 = 90+(index)*deltaAngle;
  87. float radius1 = (index == edgeWeights.EdgeCount - 1 ? edgeWeights.Weights[0] : edgeWeights.Weights[index + 1])* edgeLength;
  88. float radius2 = edgeWeights.Weights[index]*edgeLength;
  89. Vector3 p1 = new Vector3(radius1*Mathf.Cos(angle1*Mathf.Deg2Rad), radius1*Mathf.Sin(angle1*Mathf.Deg2Rad));
  90. Vector3 p2 = new Vector3(radius2 * Mathf.Cos(angle2 * Mathf.Deg2Rad), radius2 * Mathf.Sin(angle2 * Mathf.Deg2Rad));
  91. vh.AddVert(cent, color32, Vector2.zero);
  92. vh.AddVert(p1, color32, new Vector2(0,1));
  93. vh.AddVert(p2, color32, new Vector2(1,0));
  94. vh.AddTriangle(index*3, index*3 + 1, index*3 + 2);
  95. }
  96. private bool IsInPolygon(int index, float deltaAngle, Vector2 point)
  97. {
  98. float edgeLength = Mathf.Min(rectTransform.rect.width, rectTransform.rect.height)*0.5f;
  99. Vector2 cent = new Vector2(0, 0);
  100. float angle1 = 90+(index + 1) * deltaAngle;
  101. float angle2 = 90+(index) * deltaAngle;
  102. float radius1 = (index == edgeWeights.EdgeCount - 1 ? edgeWeights.Weights[0] : edgeWeights.Weights[index + 1])*edgeLength;
  103. float radius2 = edgeWeights.Weights[index]*edgeLength;
  104. Vector2 p1 = new Vector2(radius1 * Mathf.Cos(angle1 * Mathf.Deg2Rad), radius1 * Mathf.Sin(angle1 * Mathf.Deg2Rad));
  105. Vector2 p2 = new Vector2(radius2 * Mathf.Cos(angle2 * Mathf.Deg2Rad), radius2 * Mathf.Sin(angle2 * Mathf.Deg2Rad));
  106. return IsInTriangle(cent, p1, p2, point);
  107. }
  108. private bool IsInTriangle(Vector2 vertex1, Vector2 vertex2, Vector2 vertex3, Vector2 point)
  109. {
  110. Vector2 v0 =vertex3 - vertex1;
  111. Vector2 v1 = vertex2 - vertex1;
  112. Vector2 v2 = point - vertex1;
  113. float dot00 = Vector2.Dot(v0, v0);
  114. float dot01 = Vector2.Dot(v0, v1);
  115. float dot02 = Vector2.Dot(v0, v2);
  116. float dot11 = Vector2.Dot(v1, v1);
  117. float dot12 = Vector2.Dot(v1, v2);
  118. float inverDeno = 1 / (dot00 * dot11 - dot01 * dot01);
  119. float u = (dot11 * dot02 - dot01 * dot12) * inverDeno;
  120. if (u < 0 || u > 1)
  121. {
  122. return false;
  123. }
  124. float v = (dot00 * dot12 - dot01 * dot02) * inverDeno;
  125. if (v < 0 || v > 1)
  126. {
  127. return false;
  128. }
  129. return u + v <= 1;
  130. }
  131. }

 

2)PolygonImageEdge

  1. using UnityEngine;
  2. using System.Collections;
  3. using System.Collections.Generic;
  4. [System.Serializable]
  5. public class PolygonImageEdge
  6. {
  7. public int EdgeCount
  8. {
  9. get
  10. {
  11. if (m_Weights == null)
  12. return 0;
  13. return m_Weights.Count;
  14. }
  15. }
  16. public List<float> Weights
  17. {
  18. get { return m_Weights; }
  19. }
  20. [SerializeField] private List<float> m_Weights;
  21. }

 

3)PolygonImageEditor

  1. using UnityEngine;
  2. using UnityEditor.UI;
  3. using UnityEditor;
  4. using UnityEditor.UI;
  5. using System.Collections;
  6. [CustomEditor(typeof(PolygonImage))]
  7. [CanEditMultipleObjects]
  8. public class PolygonImageEditor : GraphicEditor
  9. {
  10. private SerializedProperty m_Texture;
  11. private SerializedProperty m_EdgeWeights;
  12. protected override void OnEnable()
  13. {
  14. base.OnEnable();
  15. m_Texture = serializedObject.FindProperty("m_Texture");
  16. m_EdgeWeights = serializedObject.FindProperty("edgeWeights");
  17. }
  18. protected override void OnDisable()
  19. {
  20. }
  21. public override void OnInspectorGUI()
  22. {
  23. serializedObject.Update();
  24. EditorGUILayout.PropertyField(m_Texture);
  25. EditorGUILayout.PropertyField(m_Color);
  26. EditorGUILayout.PropertyField(m_Material);
  27. EditorGUILayout.PropertyField(m_RaycastTarget);
  28. EditorGUILayout.PropertyField(m_EdgeWeights);
  29. serializedObject.ApplyModifiedProperties();
  30. }
  31. }

 

4)PolygonImageEdgeDrawer

  1. using UnityEngine;
  2. using UnityEditor;
  3. using System.Collections;
  4. using UnityEditorInternal;
  5. [CustomPropertyDrawer(typeof(PolygonImageEdge))]
  6. public class PolygonImageEdgeDrawer : PropertyDrawer
  7. {
  8. private ReorderableList m_ReorderableList;
  9. private void Init(SerializedProperty property)
  10. {
  11. if (m_ReorderableList == null)
  12. {
  13. m_ReorderableList = new ReorderableList(property.serializedObject,
  14. property.FindPropertyRelative("m_Weights"));
  15. m_ReorderableList.drawElementCallback = DrawEdgeWeight;
  16. m_ReorderableList.drawHeaderCallback = DrawHeader;
  17. }
  18. }
  19. public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
  20. {
  21. Init(property);
  22. var val = EditorGUI.indentLevel;
  23. EditorGUI.indentLevel = 0;
  24. m_ReorderableList.DoList(position);
  25. EditorGUI.indentLevel = val;
  26. }
  27. public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
  28. {
  29. Init(property);
  30. return m_ReorderableList.GetHeight();
  31. }
  32. private void DrawEdgeWeight(Rect rect, int index, bool isActive, bool isFocused)
  33. {
  34. SerializedProperty itemData = m_ReorderableList.serializedProperty.GetArrayElementAtIndex(index);
  35. EditorGUI.Slider(rect, itemData, 0, 1);
  36. }
  37. private void DrawHeader(Rect rect)
  38. {
  39. EditorGUI.LabelField(rect, "边权重");
  40. }
  41. }

 

六、雷达图 UGUI 案例

参考博文:Unity---UGUI案例学习---雷达图

1、效果图

 

2、Unity 场景布局

(这里的方法是通过改变黄色区域UI元素的外围顶点位置,来实现出我们需要的渲染效果。)

 

3、关键代码

(Point是蓝色区域最外的顶点,只需执行一次获得其具体位置就行。Handler是红色的顶点,每次更新时都要同步更新)

1)Boke_RadarChart(黄色区域雷达图类)

  1. public class Boke_RadarChart : Image
  2. {
  3. //顶点个数、顶点位置、顶点大小、顶点显示图片、顶点颜色
  4. [SerializeField]
  5. private int _pointCount;
  6. [SerializeField]
  7. private List<RectTransform> _points;
  8. [SerializeField]
  9. private Vector2 _pointSize = new Vector2(10, 10);
  10. [SerializeField]
  11. private Sprite _pointSprite;
  12. [SerializeField]
  13. private Color _pointColor = Color.white;
  14. //每个方向上各个点的的比例、存储handler
  15. [SerializeField]
  16. private float[] _handlerRadio;
  17. [SerializeField]
  18. private List<S5RadarChartHandler> _handlers;
  19. private void Update()
  20. {
  21. //刷新
  22. SetVerticesDirty();
  23. }
  24. protected override void OnPopulateMesh(VertexHelper vh)
  25. {
  26. //修改原来的空image,让他填满我们的雷达图。
  27. //清空原来顶点,自己添加
  28. vh.Clear();
  29. AddVerts(vh);
  30. //AddVertsTemplete(vh);
  31. AddTriangle(vh);
  32. }
  33. /// <summary>
  34. /// 添加顶点
  35. /// </summary>
  36. private void AddVerts(VertexHelper vh)
  37. {
  38. //添加轴心点
  39. vh.AddVert(Vector3.zero, color, Vector2.zero);
  40. foreach (S5RadarChartHandler handler in _handlers)
  41. {
  42. vh.AddVert(handler.transform.localPosition, color, Vector2.zero);
  43. }
  44. }
  45. /*
  46. /// <summary>
  47. /// 如果需要用贴图。就要每个顶点单独设置uv坐标
  48. /// </summary>
  49. private void AddVertsTemplete(VertexHelper vh)
  50. {
  51. vh.AddVert(_handlers[0].transform.localPosition, color, new Vector2(0.5f, 1));
  52. vh.AddVert(_handlers[1].transform.localPosition, color, new Vector2(0f, 1));
  53. vh.AddVert(_handlers[2].transform.localPosition, color, new Vector2(0f, 0));
  54. vh.AddVert(_handlers[3].transform.localPosition, color, new Vector2(1f, 0));
  55. vh.AddVert(_handlers[4].transform.localPosition, color, new Vector2(1f, 1));
  56. }
  57. */
  58. /// <summary>
  59. /// 添加三角形
  60. /// </summary>
  61. private void AddTriangle(VertexHelper vh)
  62. {
  63. //围绕中心点生成5个面
  64. for (int i = 1; i < _pointCount; i++)
  65. {
  66. //用三个顶点组成一个三角面
  67. //顺时针
  68. vh.AddTriangle(0, i + 1, i);
  69. }
  70. vh.AddTriangle(0, _pointCount, 1);
  71. }
  72. public void InitPoint()
  73. {
  74. ClearPoints();
  75. _points = new List<RectTransform>();
  76. SpawnPoint();
  77. SetPointPos();
  78. }
  79. private void ClearPoints()
  80. {
  81. if (_points == null)
  82. return;
  83. foreach (RectTransform point in _points)
  84. {
  85. if (point != null)
  86. //编辑模式下要用这个
  87. DestroyImmediate(point);
  88. }
  89. }
  90. private void SpawnPoint()
  91. {
  92. //5个最边角的顶点
  93. for (int i = 0; i < _pointCount; i++)
  94. {
  95. GameObject point = new GameObject("Point" + i);
  96. point.transform.SetParent(transform);
  97. _points.Add(point.AddComponent<RectTransform>());
  98. }
  99. }
  100. private void SetPointPos()
  101. {
  102. //每个角的弧度
  103. float radian = 2 * Mathf.PI / _pointCount;
  104. //半径
  105. float radius = 100;
  106. //从最上面一个顶点开始算。以中心为原点。
  107. float curRadian = 2 * Mathf.PI / 4.0f;
  108. for (int i = 0; i < _pointCount; i++)
  109. {
  110. float x = Mathf.Cos(curRadian) * radius;
  111. float y = Mathf.Sin(curRadian) * radius;
  112. curRadian += radian;
  113. _points[i].anchoredPosition = new Vector2(x, y);
  114. }
  115. }
  116. public void InitHandlers()
  117. {
  118. ClearHandlers();
  119. _handlers = new List<S5RadarChartHandler>();
  120. SpawnHandlers();
  121. SetHandlerPos();
  122. }
  123. private void ClearHandlers()
  124. {
  125. if (_handlers == null)
  126. return;
  127. foreach (S5RadarChartHandler handler in _handlers)
  128. {
  129. if (handler != null)
  130. DestroyImmediate(handler.gameObject);
  131. }
  132. }
  133. private void SpawnHandlers()
  134. {
  135. S5RadarChartHandler handler = null;
  136. for (int i = 0; i < _pointCount; i++)
  137. {
  138. GameObject point = new GameObject("Handler" + i);
  139. point.AddComponent<RectTransform>();
  140. point.AddComponent<Image>();
  141. handler = point.AddComponent<S5RadarChartHandler>();
  142. handler.SetParent(transform);
  143. handler.ChangeSprite(_pointSprite);
  144. handler.ChangeColor(_pointColor);
  145. handler.SetSize(_pointSize);
  146. handler.SetScale(Vector3.one);
  147. _handlers.Add(handler);
  148. }
  149. }
  150. private void SetHandlerPos()
  151. {
  152. //默认的handler位置,就是5项属性全满。
  153. if (_handlerRadio == null || _handlerRadio.Length != _pointCount)
  154. {
  155. for (int i = 0; i < _pointCount; i++)
  156. {
  157. _handlers[i].SetPos(_points[i].anchoredPosition);
  158. }
  159. }
  160. else
  161. {
  162. for (int i = 0; i < _pointCount; i++)
  163. {
  164. _handlers[i].SetPos(_points[i].anchoredPosition * _handlerRadio[i]);
  165. }
  166. }
  167. }
  168. }

 

2)Boke_RadarChartHandler(红色顶点类)

  1. public class Boke_RadarChartHandler : MonoBehaviour
  2. {
  3. private Image _image;
  4. private Image Image
  5. {
  6. get
  7. {
  8. if (_image == null)
  9. _image = GetComponent<Image>();
  10. return _image;
  11. }
  12. }
  13. private RectTransform _rect;
  14. private RectTransform Rect
  15. {
  16. get
  17. {
  18. if (_rect == null)
  19. _rect = GetComponent<RectTransform>();
  20. return _rect;
  21. }
  22. }
  23. #region 封装一层
  24. public void SetParent(Transform parent)
  25. {
  26. transform.SetParent(parent);
  27. }
  28. public void ChangeSprite(Sprite sprite)
  29. {
  30. Image.sprite = sprite;
  31. }
  32. public void ChangeColor(Color color)
  33. {
  34. Image.color = color;
  35. }
  36. public void SetPos(Vector2 pos)
  37. {
  38. Rect.anchoredPosition = pos;
  39. }
  40. public void SetSize(Vector2 size)
  41. {
  42. Rect.sizeDelta = size;
  43. }
  44. public void SetScale(Vector3 scale)
  45. {
  46. Rect.localScale = scale;
  47. }
  48. private float GetScale()
  49. {
  50. return Rect.lossyScale.x;
  51. }
  52. #endregion
  53. }

 

3)Boke_RadarChartEditor

(编辑器类,用于把Boke_RadarChart类中的可变属性显示到面板中,方便我们更改调试。)

  1. using System.Collections;
  2. using System.Collections.Generic;
  3. using UnityEngine;
  4. using UnityEditor;
  5. [CustomEditor(typeof(Boke_RadarChart), true)]
  6. [CanEditMultipleObjects]
  7. public class Boke_RadarChartEditor : UnityEditor.UI.ImageEditor
  8. {
  9. SerializedProperty _pointCount;
  10. SerializedProperty _pointSprite;
  11. SerializedProperty _pointColor;
  12. SerializedProperty _pointSize;
  13. SerializedProperty _handlerRadio;
  14. protected override void OnEnable()
  15. {
  16. base.OnEnable();
  17. _pointCount = serializedObject.FindProperty("_pointCount");
  18. _pointSprite = serializedObject.FindProperty("_pointSprite");
  19. _pointColor = serializedObject.FindProperty("_pointColor");
  20. _pointSize = serializedObject.FindProperty("_pointSize");
  21. _handlerRadio = serializedObject.FindProperty("_handlerRadio");
  22. }
  23. public override void OnInspectorGUI()
  24. {
  25. base.OnInspectorGUI();
  26. serializedObject.Update();
  27. EditorGUILayout.PropertyField(_pointCount);
  28. EditorGUILayout.PropertyField(_pointSprite);
  29. EditorGUILayout.PropertyField(_pointColor);
  30. EditorGUILayout.PropertyField(_pointSize);
  31. EditorGUILayout.PropertyField(_handlerRadio,true);
  32. Boke_RadarChart radar = target as Boke_RadarChart;
  33. if (radar != null)
  34. {
  35. if (GUILayout.Button("生成雷达图顶点"))
  36. {
  37. radar.InitPoint();
  38. }
  39. if (GUILayout.Button("生成内部可操作顶点"))
  40. {
  41. radar.InitHandlers();
  42. }
  43. }
  44. serializedObject.ApplyModifiedProperties();
  45. if (GUI.changed)
  46. {
  47. EditorUtility.SetDirty(target);
  48. }
  49. }
  50. }

 

最后,感谢各位博主。

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/寸_铁/article/detail/881900
推荐阅读
相关标签
  

闽ICP备14008679号