2018 年 2 月 1 日
Unity – 雷达图
【Balabalabala】
雷达图在游戏中十分常见,多用于表达人物属性,能力。
大概长这个样子:
【实现】
1.首先定义一下雷达图每个点的数据结构。
[System.Serializable] public struct RadarPointsData { public string name; [Range(0, 1)] public float percent; [Range(0, 1)] public float targetPercent; public Text nameText; public Text percentText; }
2.计算每个点的位置。
正多边形的顶点必定都在一个圆上,已知半径为R,那么其余的顶点都是01向量经过旋转得到。
向量旋转公式:
x’ = xcos(theta) – ysin(theta);
y’ = xsin(theta) + ycos(theta);
具体实现:
public void refresh()
{
if (m_RadarPoints == null || m_RadarPoints.Length == 0)
m_Vertexes = null;
else
{
RectTransform targetArea = GetComponent();
m_Vertexes = new Vector3[m_RadarPoints.Length + 1];
Vector2 rectSize = targetArea.rect.size;
Vector2 centerPos = targetArea.rect.center;
Vector3 offsetPos = new Vector3(centerPos.x, centerPos.y, 0);
float radius = Mathf.Min(rectSize.x, rectSize.y) / 2.0f;
float angle = 360.0f / m_RadarPoints.Length;
Vector3 startPos = Vector3.up;
Quaternion rotate = Quaternion.Euler(0, 0, -angle);
Vector3 nextPos = rotate * startPos;
m_Vertexes[0] = Vector3.zero + offsetPos;
m_Vertexes[1] = startPos;
for (int i = 1; i < m_RadarPoints.Length; i++)
{
m_Vertexes[i + 1] = nextPos;
nextPos = rotate * nextPos;
}
for (int i = 0; i < m_RadarPoints.Length; i++)
{
m_RadarPoints[i].percent = Mathf.Lerp(m_RadarPoints[i].percent, m_RadarPoints[i].targetPercent, 0.1f);
if (m_RadarPoints[i].percent != m_RadarPoints[i].targetPercent)
isDirty = true;
}
for (int i = 1, j = 0; i < m_Vertexes.Length; i ++, j++)
m_Vertexes[i] = m_Vertexes[i] * radius * Mathf.Clamp01(m_RadarPoints[j].percent) + offsetPos;
}
SetAllDirty();
}
3.画出多边形。
如上图所示,这个正五边形由 012、023、034、045、051, 5个三角形组成。
多边形都可以由多个三角形组成。
protected override void OnPopulateMesh(VertexHelper vh) { vh.Clear(); if (m_Vertexes != null && m_Vertexes.Length >= 2) { vh.AddVert(m_Vertexes[0], color, Vector2.zero); for (int i = 1; i < m_Vertexes.Length; i++) vh.AddVert(m_Vertexes[i], color, Vector2.zero); for (int i = 1; i < m_Vertexes.Length; i++) { if (i == m_Vertexes.Length - 1) vh.AddTriangle(0, m_Vertexes.Length - 1, 1); else vh.AddTriangle(0, i, i + 1); } vh.FillMesh(s_Mesh); } }
4.于是我们可以通过修改顶点个数,填写相应顶点的具体数据来获得想要的多边形。 将!
【给多边形添加外框】
第一反应就是给每个顶点再加一个点,延伸出线宽的距离, 再把这些点连起来。
但是一个点只能指定一个颜色,emmm,没办法,再多一个点呗。
1.再加上线框顶点的位置计算。
public void refresh()
{
if (m_RadarPoints == null || m_RadarPoints.Length == 0)
m_Vertexes = null;
else
{
RectTransform targetArea = GetComponent();
m_Vertexes = new Vector3[m_RadarPoints.Length * 3 + 1];
Vector2 rectSize = targetArea.rect.size;
Vector2 centerPos = targetArea.rect.center;
Vector3 offsetPos = new Vector3(centerPos.x, centerPos.y, 0);
float radius = Mathf.Min(rectSize.x, rectSize.y) / 2.0f;
float angle = 360.0f / m_RadarPoints.Length;
Vector3 startPos = Vector3.up;
Quaternion rotate = Quaternion.Euler(0, 0, -angle);
Vector3 nextPos = rotate * startPos;
m_Vertexes[0] = Vector3.zero + offsetPos;
m_Vertexes[1] = startPos;
m_Vertexes[2] = startPos;
m_Vertexes[3] = startPos;
for (int i = 1; i < m_RadarPoints.Length * 3 - 2; i += 3)
{
m_Vertexes[i + 3] = nextPos;
m_Vertexes[i + 4] = nextPos;
m_Vertexes[i + 5] = nextPos;
nextPos = rotate * nextPos;
}
for (int i = 0; i < m_RadarPoints.Length; i++)
{
m_RadarPoints[i].percent = Mathf.Lerp(m_RadarPoints[i].percent, m_RadarPoints[i].targetPercent, 0.1f);
if (m_RadarPoints[i].percent != m_RadarPoints[i].targetPercent)
isDirty = true;
}
for (int i = 1, j = 0; i < m_Vertexes.Length; i += 3, ++j)
{
m_Vertexes[i] = m_Vertexes[i] * radius * Mathf.Clamp01(m_RadarPoints[j].percent) + offsetPos;
m_Vertexes[i + 1] = m_Vertexes[i + 1] * radius * Mathf.Clamp01(m_RadarPoints[j].percent) + offsetPos;
m_Vertexes[i + 2] = m_Vertexes[i + 2] * (radius - m_LineWidth) * Mathf.Clamp01(m_RadarPoints[j].percent) + offsetPos;
}
}
SetAllDirty();
}
2.将这些线框顶点连起来。
protected override void OnPopulateMesh(VertexHelper vh)
{
vh.Clear();
if (m_Vertexes != null && m_Vertexes.Length >= 2)
{
vh.AddVert(m_Vertexes[0], color, Vector2.zero);
for (int i = 1; i < m_Vertexes.Length; i += 3)
{
vh.AddVert(m_Vertexes[i], color, Vector2.zero);
vh.AddVert(m_Vertexes[i + 1], m_LineColor, Vector2.zero);
vh.AddVert(m_Vertexes[i + 2], m_LineColor, Vector2.zero);
}
for (int i = 1; i < m_Vertexes.Length; i += 3)
{
if (i == m_Vertexes.Length - 3)
{
vh.AddTriangle(0, m_Vertexes.Length - 3, 1);
vh.AddTriangle(m_Vertexes.Length - 3 + 1, m_Vertexes.Length - 3 + 2, 2);
vh.AddTriangle(m_Vertexes.Length - 3 + 2, 2, 3);
}
else
{
vh.AddTriangle(0, i, i + 3);
vh.AddTriangle(i + 1, i + 2, i + 4);
vh.AddTriangle(i + 2, i + 4, i + 5);
}
}
vh.FillMesh(s_Mesh);
}
}
3.于是我们可以得到带有线框的多边形啦。将!
4.缺点
这种实现方法,在percent较小的时候,线条会变得很细,当percent为0时,甚至看不到线框。sad
(emmmm 太懒了 来日再寻找方法改进吧
【Balabalabala】
闲着无聊,发现给Radar再加个Mask组件,还挺好玩的。
(忽略这个AV画质…
【脚本】
One Comment
Excellent web site you have got here.. It’s hard to find high-quality writing
like yours nowadays. I seriously appreciate individuals like you!
Take care!!