本系列文章是学习siki学院UGUI整体解决方案-案例篇笔记
GitHub地址:https://github.com/BlueMonk1107/UGUISolution
本文实现的是雷达图,效果如下 :
项目结构如下:
实现原理大概就是根据Handle0-4顶点的位置绘制图片区域,Point0-4是生成Handle0-4的起始位置,同时Point会随着Handle移动而移动,Bg是黑色雷达图,然后根据point位置绘制中间的黄色区域
RadarChart上RadarChart脚本:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class 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;
[SerializeField]
private float[] _handlerRadio;
[SerializeField]
private List<RadarChartHandler> _handlers;
// Update is called once per frame
void Update()
{
SetVerticesDirty();
}
//绘制图形
protected override void OnPopulateMesh(VertexHelper vh)
{
vh.Clear();
AddVerts(vh);
AddTriangle(vh);
}
private void AddVerts(VertexHelper vh)
{
foreach (RadarChartHandler handler in _handlers)
{
vh.AddVert(handler.transform.localPosition, color, Vector2.zero);
}
}
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));
}
private void AddTriangle(VertexHelper vh)
{
for (int i = 1; i < _pointCount - 1; i++)
{
vh.AddTriangle(0,i+1,i);
}
}
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()
{
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<RadarChartHandler>();
SpawnHandlers();
SetHandlerPos();
}
private void ClearHandlers()
{
if (_handlers == null)
return;
foreach (RadarChartHandler handler in _handlers)
{
if (handler != null)
DestroyImmediate(handler.gameObject);
}
}
private void SpawnHandlers()
{
RadarChartHandler handler = null;
for (int i = 0; i < _pointCount; i++)
{
GameObject point = new GameObject("Handler" + i);
point.AddComponent<RectTransform>();
point.AddComponent<Image>();
handler = point.AddComponent<RadarChartHandler>();
handler.SetParent(transform);
handler.ChangeSprite(_pointSprite);
handler.ChangeColor(_pointColor);
handler.SetSize(_pointSize);
handler.SetScale(Vector3.one);
_handlers.Add(handler);
}
}
private void SetHandlerPos()
{
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]);
}
}
}
}
Handle上RadarChartHandler脚本:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;
public class RadarChartHandler : MonoBehaviour,IDragHandler
{
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;
}
}
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;
}
public void OnDrag(PointerEventData eventData)
{
Rect.anchoredPosition += eventData.delta/ GetScale();
}
private float GetScale()
{
return Rect.lossyScale.x;
}
}
两个按钮编辑器脚本RadarChartEditor:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
[CustomEditor(typeof(RadarChart), true)]
[CanEditMultipleObjects]
public class 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);
RadarChart radar = target as RadarChart;
if (radar != null)
{
if (GUILayout.Button("生成雷达图顶点"))
{
radar.InitPoint();
}
if (GUILayout.Button("生成内部可操作顶点"))
{
radar.InitHandlers();
}
}
serializedObject.ApplyModifiedProperties();
if (GUI.changed)
{
EditorUtility.SetDirty(target);
}
}
}