221 lines
6.3 KiB
C#
221 lines
6.3 KiB
C#
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;
|
||
}
|
||
}
|
||
}
|