killapp/Assets/Scripts/UI/Components/RadarHeatmap.cs
“虞渠成” 7b5272b468 0608
2026-06-08 08:55:10 +08:00

221 lines
6.3 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
namespace Kill.UI.Components
{
/// <summary>
/// 雷达热力图组件
/// 在雷达图图片上根据角度(0-180度)和距离数据显示热力点
/// 角度定义左侧0度正上方90度右侧180度
/// </summary>
public class RadarHeatmap : MonoBehaviour
{
[Header("雷达图背景")]
[Tooltip("雷达图背景图片")]
public Image radarBackground;
[Tooltip("雷达图半径(从中心到边缘的距离)")]
public float radius = 200f;
[Header("热力点预设")]
[Tooltip("热力点预制体")]
public GameObject heatPointPrefab;
// 数据点列表
private List<HeatmapData> dataPoints = new List<HeatmapData>();
// 热力点对象池
private List<GameObject> heatPointPool = new List<GameObject>();
// 容器
public RectTransform heatPointContainer;
/// <summary>
/// 热力图数据点
/// </summary>
[Serializable]
public class HeatmapData
{
[Tooltip("角度 (0-180度左侧为0度正上方为90度右侧为180度)")]
[Range(0f, 180f)]
public float angle;
[Tooltip("距离 (0-1相对于雷达半径的比例)")]
[Range(0f, 1f)]
public float distance;
[Tooltip("自定义数据")]
public object customData;
public HeatmapData(float angle, float distance, object customData = null)
{
this.angle = Mathf.Clamp(angle, 0f, 180f);
this.distance = Mathf.Clamp01(distance);
this.customData = customData;
}
}
private void Awake()
{
InitializeContainer();
}
/// <summary>
/// 初始化容器
/// </summary>
private void InitializeContainer()
{
// 如果没有指定背景图片尝试获取自身的Image
if (radarBackground == null)
{
radarBackground = GetComponent<Image>();
}
}
/// <summary>
/// 设置数据并刷新热力图
/// </summary>
public void SetData(List<HeatmapData> data)
{
dataPoints = data ?? new List<HeatmapData>();
RefreshHeatmap();
}
/// <summary>
/// 添加单个数据点
/// </summary>
public void AddDataPoint(HeatmapData data)
{
dataPoints.Add(data);
CreateHeatPoint(data);
}
/// <summary>
/// 清除所有数据
/// </summary>
public void ClearData()
{
dataPoints.Clear();
RefreshHeatmap();
}
/// <summary>
/// 刷新热力图显示
/// </summary>
private void RefreshHeatmap()
{
// 回收所有热力点
foreach (var point in heatPointPool)
{
if (point != null)
{
point.SetActive(false);
}
}
// 创建新的热力点
for (int i = 0; i < dataPoints.Count; i++)
{
if (i < heatPointPool.Count)
{
UpdateHeatPoint(heatPointPool[i], dataPoints[i]);
}
else
{
CreateHeatPoint(dataPoints[i]);
}
}
}
/// <summary>
/// 创建热力点
/// </summary>
private void CreateHeatPoint(HeatmapData data)
{
if (heatPointPrefab == null)
{
Debug.LogError("[RadarHeatmap] 热力点预制体未设置!");
return;
}
GameObject pointObj = Instantiate(heatPointPrefab, heatPointContainer);
RectTransform rect = pointObj.GetComponent<RectTransform>();
// 计算位置
Vector2 position = CalculatePosition(data.angle, data.distance);
rect.anchoredPosition = position;
heatPointPool.Add(pointObj);
}
/// <summary>
/// 更新热力点
/// </summary>
private void UpdateHeatPoint(GameObject pointObj, HeatmapData data)
{
if (pointObj == null) return;
pointObj.SetActive(true);
RectTransform rect = pointObj.GetComponent<RectTransform>();
// 更新位置
Vector2 position = CalculatePosition(data.angle, data.distance);
rect.anchoredPosition = position;
}
/// <summary>
/// 计算数据点在雷达图上的位置
/// 角度定义左侧0度正上方90度右侧180度
/// </summary>
private Vector2 CalculatePosition(float angle, float distance)
{
// 将角度转换为弧度
// 左侧0度 -> 180度正上方90度 -> 90度
// 转换为标准极坐标0度为正右方逆时针增加
// 所以左侧0度 = 180度正上方90度 = 90度右侧180度 = 0度
float standardAngle = 180f - angle;
float radian = standardAngle * Mathf.Deg2Rad;
// 计算实际距离
float actualDistance = distance * radius;
// 计算坐标
float x = Mathf.Cos(radian) * actualDistance;
float y = Mathf.Sin(radian) * actualDistance;
return new Vector2(x, y);
}
/// <summary>
/// 设置雷达图半径
/// </summary>
public void SetRadius(float newRadius)
{
radius = newRadius;
RefreshHeatmap();
}
/// <summary>
/// 获取数据点数量
/// </summary>
public int GetDataPointCount()
{
return dataPoints.Count;
}
/// <summary>
/// 获取指定索引的数据点
/// </summary>
public HeatmapData GetDataPoint(int index)
{
if (index >= 0 && index < dataPoints.Count)
{
return dataPoints[index];
}
return null;
}
}
}