目录
1、雷达图
最后效果
这里的方法是通过改变黄色区域UI元素的外围顶点位置,来实现出我们需要的渲染效果。
Point是蓝色区域最外的顶点,只需执行一次获得其具体位置就行。
Handler是红色的顶点,每次更新时都要同步更新
黄色区域雷达图类
public class Boke_RadarChart : Image
{
//顶点个数、顶点位置、顶点大小、顶点显示图片、顶点颜色
[SerializeField]
private int _pointCount;
[SerializeField]
private List<RectTransform> _points;
[SerializeField]
private Vector2 _pointSize = new Vector2(10, 10);
[SerializeField]
private Sprite _pointSprite;
[SerializeField]
private Color _pointColor = Color.white;
//每个方向上各个点的的比例、存储handler
[SerializeField]
private float[] _handlerRadio;
[SerializeField]
private List<S5RadarChartHandler> _handlers;
private void Update()
{
//刷新
SetVerticesDirty();
}
protected override void OnPopulateMesh(VertexHelper vh)
{
//修改原来的空image,让他填满我们的雷达图。
//清空原来顶点,自己添加
vh.Clear();
AddVerts(vh);
//AddVertsTemplete(vh);
AddTriangle(vh);
}
/// <summary>
/// 添加顶点
/// </summary>
private void AddVerts(VertexHelper vh)
{
//添加轴心点
vh.AddVert(Vector3.zero, color, Vector2.zero);
foreach (S5RadarChartHandler handler in _handlers)
{
vh.AddVert(handler.transform.localPosition, color, Vector2.zero);
}
}
/*
/// <summary>
/// 如果需要用贴图。就要每个顶点单独设置uv坐标
/// </summary>
private void AddVertsTemplete(VertexHelper vh)
{
vh.AddVert(_handlers[0].transform.localPosition, color, new Vector2(0.5f, 1));
vh.AddVert(_handlers[1].transform.localPosition, color, new Vector2(0f, 1));
vh.AddVert(_handlers[2].transform.localPosition, color, new Vector2(0f, 0));
vh.AddVert(_handlers[3].transform.localPosition, color, new Vector2(1f, 0));
vh.AddVert(_handlers[4].transform.localPosition, color, new Vector2(1f, 1));
}
*/
/// <summary>
/// 添加三角形
/// </summary>
private void AddTriangle(VertexHelper vh)
{
//围绕中心点生成5个面
for (int i = 1; i < _pointCount; i++)
{
//用三个顶点组成一个三角面
//顺时针
vh.AddTriangle(0, i + 1, i);
}
vh.AddTriangle(0, _pointCount, 1);
}
public void InitPoint()
{
ClearPoints();
_points = new List<RectTransform>();
SpawnPoint();
SetPointPos();
}
private void ClearPoints()
{
if (_points == null)
return;
foreach (RectTransform point in _points)
{
if (point != null)
//编辑模式下要用这个
DestroyImmediate(point);
}
}
private void SpawnPoint()
{
//5个最边角的顶点
for (int i = 0; i < _pointCount; i++)
{
GameObject point = new GameObject("Point" + i);
point.transform.SetParent(transform);
_points.Add(point.AddComponent<RectTransform>());
}
}
private void SetPointPos()
{
//每个角的弧度
float radian = 2 * Mathf.PI / _pointCount;
//半径
float radius = 100;
//从最上面一个顶点开始算。以中心为原点。
float curRadian = 2 * Mathf.PI / 4.0f;
for (int i = 0; i < _pointCount; i++)
{
float x = Mathf.Cos(curRadian) * radius;
float y = Mathf.Sin(curRadian) * radius;
curRadian += radian;
_points[i].anchoredPosition = new Vector2(x, y);
}
}
public void InitHandlers()
{
ClearHandlers();
_handlers = new List<S5RadarChartHandler>();
SpawnHandlers();
SetHandlerPos();
}
private void ClearHandlers()
{
if (_handlers == null)
return;
foreach (S5RadarChartHandler handler in _handlers)
{
if (handler != null)
DestroyImmediate(handler.gameObject);
}
}
private void SpawnHandlers()
{
S5RadarChartHandler handler = null;
for (int i = 0; i < _pointCount; i++)
{
GameObject point = new GameObject("Handler" + i);
point.AddComponent<RectTransform>();
point.AddComponent<Image>();
handler = point.AddComponent<S5RadarChartHandler>();
handler.SetParent(transform);
handler.ChangeSprite(_pointSprite);
handler.ChangeColor(_pointColor);
handler.SetSize(_pointSize);
handler.SetScale(Vector3.one);
_handlers.Add(handler);
}
}
private void SetHandlerPos()
{
//默认的handler位置,就是5项属性全满。
if (_handlerRadio == null || _handlerRadio.Length != _pointCount)
{
for (int i = 0; i < _pointCount; i++)
{
_handlers[i].SetPos(_points[i].anchoredPosition);
}
}
else
{
for (int i = 0; i < _pointCount; i++)
{
_handlers[i].SetPos(_points[i].anchoredPosition * _handlerRadio[i]);
}
}
}
}
红色顶点类
public class Boke_RadarChartHandler : MonoBehaviour
{
private Image _image;
private Image Image
{
get
{
if (_image == null)
_image = GetComponent<Image>();
return _image;
}
}
private RectTransform _rect;
private RectTransform Rect
{
get
{
if (_rect == null)
_rect = GetComponent<RectTransform>();
return _rect;
}
}
#region 封装一层
public void SetParent(Transform parent)
{
transform.SetParent(parent);
}
public void ChangeSprite(Sprite sprite)
{
Image.sprite = sprite;
}
public void ChangeColor(Color color)
{
Image.color = color;
}
public void SetPos(Vector2 pos)
{
Rect.anchoredPosition = pos;
}
public void SetSize(Vector2 size)
{
Rect.sizeDelta = size;
}
public void SetScale(Vector3 scale)
{
Rect.localScale = scale;
}
private float GetScale()
{
return Rect.lossyScale.x;
}
#endregion
}
编辑器类,用于把Boke_RadarChart类中的可变属性显示到面板中,方便我们更改调试。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
[CustomEditor(typeof(Boke_RadarChart), true)]
[CanEditMultipleObjects]
public class Boke_RadarChartEditor : UnityEditor.UI.ImageEditor
{
SerializedProperty _pointCount;
SerializedProperty _pointSprite;
SerializedProperty _pointColor;
SerializedProperty _pointSize;
SerializedProperty _handlerRadio;
protected override void OnEnable()
{
base.OnEnable();
_pointCount = serializedObject.FindProperty("_pointCount");
_pointSprite = serializedObject.FindProperty("_pointSprite");
_pointColor = serializedObject.FindProperty("_pointColor");
_pointSize = serializedObject.FindProperty("_pointSize");
_handlerRadio = serializedObject.FindProperty("_handlerRadio");
}
public override void OnInspectorGUI()
{
base.OnInspectorGUI();
serializedObject.Update();
EditorGUILayout.PropertyField(_pointCount);
EditorGUILayout.PropertyField(_pointSprite);
EditorGUILayout.PropertyField(_pointColor);
EditorGUILayout.PropertyField(_pointSize);
EditorGUILayout.PropertyField(_handlerRadio,true);
Boke_RadarChart radar = target as Boke_RadarChart;
if (radar != null)
{
if (GUILayout.Button("生成雷达图顶点"))
{
radar.InitPoint();
}
if (GUILayout.Button("生成内部可操作顶点"))
{
radar.InitHandlers();
}
}
serializedObject.ApplyModifiedProperties();
if (GUI.changed)
{
EditorUtility.SetDirty(target);
}
}
}