目錄
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);
}
}
}