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;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|