using System.Collections.Generic; using TMPro; using UnityEngine; using UnityEngine.UI; /// /// UI兼容的图表组件 /// 使用UI Image和RectTransform在Canvas中绘制折线图,替代LineRenderer /// public class UIChartComponent : MonoBehaviour { [Header("图表设置")] public RectTransform chartArea; public TextMeshProUGUI valueLabel; public TextMeshProUGUI titleLabel; public Color lineColor = Color.green; public float lineWidth = 2f; [Header("数据设置")] public int maxDataPoints = 50; public float minValue = 0f; public float maxValue = 100f; public string unit = ""; [Header("UI设置")] public GameObject linePrefab; // 预制件:包含Image组件的GameObject public Transform lineParent; // 折线段的父物体 private List dataPoints = new List(); private List lineSegments = new List(); void Awake() { InitializeChart(); } /// /// 初始化图表 /// private void InitializeChart() { // 如果没有设置lineParent,使用chartArea if (lineParent == null && chartArea != null) { lineParent = chartArea; } // 如果没有linePrefab,创建一个默认的 if (linePrefab == null) { CreateDefaultLinePrefab(); } } /// /// 创建默认的线段预制件 /// private void CreateDefaultLinePrefab() { linePrefab = new GameObject("LineSegment"); // 添加RectTransform var rectTransform = linePrefab.AddComponent(); rectTransform.anchorMin = new Vector2(0.5f, 0.5f); rectTransform.anchorMax = new Vector2(0.5f, 0.5f); rectTransform.pivot = new Vector2(0.5f, 0.5f); // 添加Image组件 var image = linePrefab.AddComponent(); image.color = lineColor; // 设置为预制件状态 linePrefab.SetActive(false); } /// /// 添加数据点 /// public void AddDataPoint(float value) { dataPoints.Add(value); // 保持最大数据点数量 if (dataPoints.Count > maxDataPoints) { dataPoints.RemoveAt(0); } UpdateChart(); UpdateValueLabel(value); } /// /// 更新图表显示 /// private void UpdateChart() { if (chartArea == null || lineParent == null) { return; } int requiredSegmentCount = Mathf.Max(0, dataPoints.Count - 1); EnsureLineSegmentCount(requiredSegmentCount); var rect = chartArea.rect; var width = rect.width; var height = rect.height; for (int i = 0; i < lineSegments.Count; i++) { var segment = lineSegments[i]; if (segment == null) { continue; } bool active = i < requiredSegmentCount; if (segment.activeSelf != active) { segment.SetActive(active); } if (!active) { continue; } Vector2 point1 = CalculatePointPosition(i, dataPoints[i], width, height); Vector2 point2 = CalculatePointPosition(i + 1, dataPoints[i + 1], width, height); UpdateLineSegment(segment, point1, point2); } } /// /// 计算数据点在图表中的位置 /// private Vector2 CalculatePointPosition(int index, float value, float width, float height) { float x = (float)index / (maxDataPoints - 1) * width - width / 2; float y = Mathf.Lerp(-height / 2, height / 2, Mathf.InverseLerp(minValue, maxValue, value)); return new Vector2(x, y); } /// /// 创建线段 /// private void EnsureLineSegmentCount(int requiredCount) { if (linePrefab == null) { return; } while (lineSegments.Count < requiredCount) { GameObject segment = Instantiate(linePrefab, lineParent); segment.SetActive(false); lineSegments.Add(segment); } } private void UpdateLineSegment(GameObject segment, Vector2 point1, Vector2 point2) { if (segment == null) return; RectTransform segmentRect = segment.GetComponent(); Image segmentImage = segment.GetComponent(); if (segmentRect == null) return; // 计算线段的位置、长度和角度 Vector2 direction = point2 - point1; float length = direction.magnitude; float angle = Mathf.Atan2(direction.y, direction.x) * Mathf.Rad2Deg; // 设置线段位置(中心点) segmentRect.anchoredPosition = (point1 + point2) / 2; // 设置线段大小(宽度为lineWidth,高度为长度) segmentRect.sizeDelta = new Vector2(length, lineWidth); // 设置线段旋转 segmentRect.rotation = Quaternion.Euler(0, 0, angle); // 设置颜色 if (segmentImage != null) { segmentImage.color = lineColor; } } /// /// 清除所有线段 /// private void ClearLineSegments() { foreach (var segment in lineSegments) { if (segment != null) { Destroy(segment); } } lineSegments.Clear(); } /// /// 更新数值标签 /// private void UpdateValueLabel(float value) { if (valueLabel != null) { valueLabel.text = value.ToString("F1") + unit; } } /// /// 设置图表标题 /// public void SetTitle(string title) { if (titleLabel != null) { titleLabel.text = title; } } /// /// 设置线条颜色 /// public void SetLineColor(Color color) { lineColor = color; // 更新现有线段的颜色 foreach (var segment in lineSegments) { if (segment != null) { var image = segment.GetComponent(); if (image != null) { image.color = lineColor; } } } } /// /// 设置值范围 /// public void SetValueRange(float min, float max) { minValue = min; maxValue = max; UpdateChart(); // 重新绘制图表以应用新范围 } /// /// 清空数据 /// public void ClearData() { dataPoints.Clear(); ClearLineSegments(); if (valueLabel != null) { valueLabel.text = "0.0" + unit; } } /// /// 获取当前数据点数量 /// public int GetDataPointCount() { return dataPoints.Count; } /// /// 获取最新的数据值 /// public float GetLatestValue() { return dataPoints.Count > 0 ? dataPoints[dataPoints.Count - 1] : 0f; } void OnDestroy() { ClearLineSegments(); } }