194 lines
5.0 KiB
C#
Raw Normal View History

2025-05-18 01:04:31 +08:00
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using UnityEngine.UI;
namespace G.UI
{
public class RadarChart : Image
{
// Start is called before the first frame update
[SerializeField]
public int _pointCount;
[SerializeField]
public List<RectTransform> _points = new List<RectTransform>();
[SerializeField]
private Vector2 _pointSize = new Vector2(10, 10);
[SerializeField]
private Sprite _pointSprite;
[SerializeField]
private Color _pointColor = Color.white;
[SerializeField]
public List<RadarChartHandler> _handlers = new List<RadarChartHandler>();
[SerializeField]
private float[] _handlerRadio;
public float[] radio
{
get { return _handlerRadio; }
}
private void Update()
{
SetVerticesDirty(); //实时对顶点数据刷新
}
protected override void OnPopulateMesh(VertexHelper vertexHelper)
{
vertexHelper.Clear();
if (_handlers != null && _handlers.Count > 0)
if (!_handlers[0])
_handlers.Clear();
if (_handlers != null && _handlers.Count == 0)
return;
AddVerts(vertexHelper); //添加全部顶点信息
//AddVertsPlate(vertexHelper);
AddTriangles(vertexHelper); //添加全部面信息
}
/// <summary>
/// 添加顶点
/// </summary>
/// <param name="vh"></param>
private void AddVerts(VertexHelper vh)
{
vh.AddVert(transform.localPosition, color, Vector2.one);
foreach (var handler in _handlers)
{
vh.AddVert(handler.transform.localPosition, color, Vector2.zero);
}
}
/// <summary>
/// 添加顶点模板 制作带sprite的雷达图效果
/// </summary>
/// <param name="vh"></param>
private void AddVertsPlate(VertexHelper vh)
{
if (_handlers != null && _handlers.Count > 0)
{
if (!_handlers[0])
{
_handlers.Clear();
return;
}
vh.AddVert(_handlers[0].transform.localPosition, color, new Vector2(0.5f, 1.0f));
vh.AddVert(_handlers[1].transform.localPosition, color, new Vector2(0f, 1.0f));
vh.AddVert(_handlers[2].transform.localPosition, color, new Vector2(0f, 0f));
vh.AddVert(_handlers[3].transform.localPosition, color, new Vector2(1.0f, 0f));
vh.AddVert(_handlers[4].transform.localPosition, color, new Vector2(1.0f, 1.0f));
}
}
private void AddTriangles(VertexHelper vh) //UI.Default.shader 默认剔除是关闭的,模型黑面,很奇怪(法向量搞反)
{
for (int i = 1; i <= _pointCount - 1; i++)
{
vh.AddTriangle(0, i + 1, i);
}
vh.AddTriangle(0, 1, 5);
}
public void InitPoints()
{
ClearPoints();
_points = new List<RectTransform>();
_handlers = new List<RadarChartHandler>();
SpawnPoints();
SetPointPos();
}
private void SpawnPoints() //生成 point
{
for (var i = 0; i < _pointCount; i++)
{
var point = new GameObject("Point" + i);
point.transform.SetParent(transform);
_points.Add(point.AddComponent<RectTransform>());
}
}
private void ClearPoints()
{
if (_points == null) return;
foreach (var point in _points.Where(point => point != null))
{
DestroyImmediate(point); //在编译时也能进行
}
}
private void ClearHandles()
{
if (_handlers == null) return;
for (int i = _handlers.Count - 1; i >= 0; i--)
{
if (_handlers[i])
{
DestroyImmediate(_handlers[i].gameObject);
}
}
_handlers.Clear();
}
private void SetPointPos() //设置点坐标
{
float radian = 2 * Mathf.PI / _pointCount; //计算出当前多边形的每一段对应填充圆的弧长
float radius = 130; //暂定当前正多边形的所填充圆的半径为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()
{
ClearHandles();
SpawnHandlers();
SetHandlerPos();
}
private void SpawnHandlers()
{
for (int i = 0; i < _pointCount; i++)
{
if (i < _handlers.Count)
{
continue;
}
var go = new GameObject("Handler" + i);
go.AddComponent<RectTransform>();
go.AddComponent<Image>();
var handler = go.AddComponent<RadarChartHandler>();
handler.transform.SetParent(transform, false);
handler.ChangeColor(_pointColor);
handler.ChangeSprite(_pointSprite);
handler.SetSize(_pointSize);
_handlers.Add(handler);
}
}
private void SetHandlerPos()
{
if (_handlerRadio == null || _handlerRadio.Length != _pointCount)
{
for (var i = 0; i < _pointCount; i++)
{
if (_handlers[i])
_handlers[i].SetPos(_points[i].anchoredPosition);
}
}
else
{
for (var i = 0; i < _pointCount; i++)
{
if (_handlers[i])
_handlers[i].SetPos(_points[i].anchoredPosition * _handlerRadio[i]);
}
}
}
}
}