Files
bansonic_beta_main/Assets/playerInfoDisplay/uRader/UIRadarGraphic.cs
T
2026-06-30 21:21:30 +08:00

276 lines
9.9 KiB
C#

using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
[RequireComponent(typeof(CanvasRenderer))]
public class UIRadarGraphic : MaskableGraphic
{
private const float MainStrokeWidth = 2.5f;
private const float ReferenceStrokeWidth = 2f;
private const float MainPointSize = 8f;
private const float ReferencePointSize = 7f;
private readonly List<URadarAxisEntry> axisEntries = new List<URadarAxisEntry>();
private float minValue;
private float maxValue = 100f;
private int splitCount = 5;
private bool showReferenceSeries;
private Color gridLineColor = new Color32(255, 255, 255, 180);
private Color outerGridLineColor = Color.white;
private float gridLineWidth = 2f;
private Color mainStrokeColor = new Color32(82, 126, 255, 255);
private Color mainFillColor = new Color(82f / 255f, 126f / 255f, 255f / 255f, 0.28f);
private Color mainPointColor = Color.white;
private Color referenceStrokeColor = new Color32(72, 229, 229, 255);
private Color referenceFillColor = new Color(72f / 255f, 229f / 255f, 229f / 255f, 0.22f);
private Color referencePointColor = Color.white;
private float radarPlotPadding = 8f;
private float radarInnerRadius;
private float radarLabelRadialOffset;
public void SetData(
List<URadarAxisEntry> sourceAxes,
float sourceMinValue,
float sourceMaxValue,
int sourceSplitCount,
bool sourceShowReferenceSeries,
Color sourceGridLineColor,
Color sourceOuterGridLineColor,
float sourceGridLineWidth,
Color sourceMainStrokeColor,
Color sourceMainFillColor,
Color sourceMainPointColor,
Color sourceReferenceStrokeColor,
Color sourceReferenceFillColor,
Color sourceReferencePointColor,
float sourceRadarPlotPadding,
float sourceRadarInnerRadius,
float sourceRadarLabelRadialOffset)
{
axisEntries.Clear();
if (sourceAxes != null)
{
for (int i = 0; i < sourceAxes.Count; i++)
{
URadarAxisEntry source = sourceAxes[i];
if (source == null)
{
axisEntries.Add(new URadarAxisEntry());
continue;
}
axisEntries.Add(new URadarAxisEntry
{
label = source.label,
value = source.value,
referenceValue = source.referenceValue
});
}
}
minValue = sourceMinValue;
maxValue = Mathf.Max(sourceMinValue + 0.0001f, sourceMaxValue);
splitCount = Mathf.Max(2, sourceSplitCount);
showReferenceSeries = sourceShowReferenceSeries;
gridLineColor = sourceGridLineColor;
outerGridLineColor = sourceOuterGridLineColor;
gridLineWidth = Mathf.Max(0.1f, sourceGridLineWidth);
mainStrokeColor = sourceMainStrokeColor;
mainFillColor = sourceMainFillColor;
mainPointColor = sourceMainPointColor;
referenceStrokeColor = sourceReferenceStrokeColor;
referenceFillColor = sourceReferenceFillColor;
referencePointColor = sourceReferencePointColor;
radarPlotPadding = Mathf.Max(0f, sourceRadarPlotPadding);
radarInnerRadius = Mathf.Max(0f, sourceRadarInnerRadius);
radarLabelRadialOffset = sourceRadarLabelRadialOffset;
SetVerticesDirty();
}
protected override void OnPopulateMesh(VertexHelper vh)
{
vh.Clear();
if (axisEntries.Count < 3)
{
return;
}
Rect rect = GetPixelAdjustedRect();
Vector2 center = rect.center;
float maxRadius = Mathf.Max(0f, Mathf.Min(rect.width, rect.height) * 0.5f - radarPlotPadding - Mathf.Max(MainPointSize, ReferencePointSize));
float innerRadius = Mathf.Clamp(radarInnerRadius, 0f, maxRadius * 0.8f);
DrawGrid(vh, center, innerRadius, maxRadius);
List<Vector2> mainPoints = BuildSeriesPoints(center, innerRadius, maxRadius, false);
if (showReferenceSeries)
{
List<Vector2> referencePoints = BuildSeriesPoints(center, innerRadius, maxRadius, true);
DrawFilledPolygon(vh, center, referencePoints, referenceFillColor);
DrawPolyline(vh, referencePoints, true, ReferenceStrokeWidth, referenceStrokeColor);
DrawPointMarkers(vh, referencePoints, ReferencePointSize, referencePointColor);
}
DrawFilledPolygon(vh, center, mainPoints, mainFillColor);
DrawPolyline(vh, mainPoints, true, MainStrokeWidth, mainStrokeColor);
DrawPointMarkers(vh, mainPoints, MainPointSize, mainPointColor);
}
private void DrawGrid(VertexHelper vh, Vector2 center, float innerRadius, float maxRadius)
{
int axisCount = axisEntries.Count;
for (int ring = 1; ring <= splitCount; ring++)
{
float t = ring / (float)splitCount;
float radius = Mathf.Lerp(innerRadius, maxRadius, t);
List<Vector2> ringPoints = new List<Vector2>(axisCount);
for (int i = 0; i < axisCount; i++)
{
ringPoints.Add(GetAxisPoint(center, radius, i, axisCount));
}
DrawPolyline(vh, ringPoints, true, gridLineWidth, ring == splitCount ? outerGridLineColor : gridLineColor);
}
for (int i = 0; i < axisCount; i++)
{
Vector2 start = GetAxisPoint(center, innerRadius, i, axisCount);
Vector2 end = GetAxisPoint(center, maxRadius, i, axisCount);
DrawLine(vh, start, end, gridLineWidth, gridLineColor);
}
}
private List<Vector2> BuildSeriesPoints(Vector2 center, float innerRadius, float maxRadius, bool useReferenceValue)
{
int axisCount = axisEntries.Count;
List<Vector2> points = new List<Vector2>(axisCount);
for (int i = 0; i < axisCount; i++)
{
URadarAxisEntry entry = axisEntries[i];
float value = useReferenceValue ? entry.referenceValue : entry.value;
float normalized = Mathf.InverseLerp(minValue, maxValue, Mathf.Clamp(value, minValue, maxValue));
float radius = Mathf.Lerp(innerRadius, maxRadius, normalized);
points.Add(GetAxisPoint(center, radius, i, axisCount));
}
return points;
}
private static Vector2 GetAxisPoint(Vector2 center, float radius, int axisIndex, int axisCount)
{
float angle = Mathf.PI * 0.5f - (Mathf.PI * 2f / axisCount) * axisIndex;
return center + new Vector2(Mathf.Cos(angle), Mathf.Sin(angle)) * radius;
}
private static void DrawFilledPolygon(VertexHelper vh, Vector2 center, List<Vector2> points, Color color)
{
if (points == null || points.Count < 3 || color.a <= 0f)
{
return;
}
int startIndex = vh.currentVertCount;
UIVertex centerVertex = UIVertex.simpleVert;
centerVertex.color = color;
centerVertex.position = center;
vh.AddVert(centerVertex);
for (int i = 0; i < points.Count; i++)
{
UIVertex vertex = UIVertex.simpleVert;
vertex.color = color;
vertex.position = points[i];
vh.AddVert(vertex);
}
for (int i = 0; i < points.Count; i++)
{
int current = startIndex + 1 + i;
int next = startIndex + 1 + ((i + 1) % points.Count);
vh.AddTriangle(startIndex, current, next);
}
}
private static void DrawPolyline(VertexHelper vh, List<Vector2> points, bool closed, float thickness, Color color)
{
if (points == null || points.Count < 2 || color.a <= 0f || thickness <= 0f)
{
return;
}
for (int i = 0; i < points.Count - 1; i++)
{
DrawLine(vh, points[i], points[i + 1], thickness, color);
}
if (closed)
{
DrawLine(vh, points[points.Count - 1], points[0], thickness, color);
}
}
private static void DrawLine(VertexHelper vh, Vector2 start, Vector2 end, float thickness, Color color)
{
Vector2 delta = end - start;
if (delta.sqrMagnitude <= 0.0001f)
{
return;
}
Vector2 normal = new Vector2(-delta.y, delta.x).normalized * (thickness * 0.5f);
int index = vh.currentVertCount;
UIVertex vertex = UIVertex.simpleVert;
vertex.color = color;
vertex.position = start - normal;
vh.AddVert(vertex);
vertex.position = start + normal;
vh.AddVert(vertex);
vertex.position = end + normal;
vh.AddVert(vertex);
vertex.position = end - normal;
vh.AddVert(vertex);
vh.AddTriangle(index, index + 1, index + 2);
vh.AddTriangle(index, index + 2, index + 3);
}
private static void DrawPointMarkers(VertexHelper vh, List<Vector2> points, float size, Color color)
{
if (points == null || color.a <= 0f || size <= 0f)
{
return;
}
float half = size * 0.5f;
for (int i = 0; i < points.Count; i++)
{
DrawQuad(vh, points[i], new Vector2(half, half), color);
}
}
private static void DrawQuad(VertexHelper vh, Vector2 center, Vector2 halfSize, Color color)
{
int index = vh.currentVertCount;
UIVertex vertex = UIVertex.simpleVert;
vertex.color = color;
vertex.position = new Vector2(center.x - halfSize.x, center.y - halfSize.y);
vh.AddVert(vertex);
vertex.position = new Vector2(center.x - halfSize.x, center.y + halfSize.y);
vh.AddVert(vertex);
vertex.position = new Vector2(center.x + halfSize.x, center.y + halfSize.y);
vh.AddVert(vertex);
vertex.position = new Vector2(center.x + halfSize.x, center.y - halfSize.y);
vh.AddVert(vertex);
vh.AddTriangle(index, index + 1, index + 2);
vh.AddTriangle(index, index + 2, index + 3);
}
}