using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
namespace KhawajjaGames.HUD
{
///
/// Tactical 3D Combat Radar and Minimap Compass System for Unity.
/// Tracks enemy fighter jets, friendly units, missile threats, and mission objectives.
/// Created by Khawajja Games Studio (https://khawajjagames.com)
///
public class MinimapRadar : MonoBehaviour
{
public enum BlipType { Enemy, Friendly, Objective, Hazard }
[System.Serializable]
public class RadarBlip
{
public Transform targetTransform;
public BlipType type;
[HideInInspector] public Image iconInstance;
}
[Header("Radar Center & Range")]
[Tooltip("The player aircraft or ship at the center of the radar")]
public Transform playerTransform;
[Tooltip("World radius tracked inside the radar display")]
public float radarWorldRadius = 1500f;
[Tooltip("Radar UI display radius in screen pixels")]
public float radarUIRadius = 120f;
[Header("UI References")]
public RectTransform radarUIPanel;
public GameObject blipPrefab;
[Header("Blip Colors")]
public Color enemyColor = new Color(1f, 0.2f, 0.2f, 1f);
public Color friendlyColor = new Color(0.2f, 0.8f, 1f, 1f);
public Color objectiveColor = new Color(1f, 0.8f, 0.1f, 1f);
public Color hazardColor = new Color(1f, 0.4f, 0f, 1f);
[Header("Rotation Settings")]
[Tooltip("Rotate radar with player heading (true) or fixed North (false)")]
public bool rotateWithPlayer = true;
private List _trackedBlips = new List();
private void LateUpdate()
{
if (playerTransform == null || radarUIPanel == null) return;
UpdateRadarBlips();
}
public void RegisterTarget(Transform target, BlipType type)
{
if (target == null) return;
RadarBlip newBlip = new RadarBlip
{
targetTransform = target,
type = type
};
if (blipPrefab != null && radarUIPanel != null)
{
GameObject iconObj = Instantiate(blipPrefab, radarUIPanel);
newBlip.iconInstance = iconObj.GetComponent();
if (newBlip.iconInstance != null)
{
newBlip.iconInstance.color = GetBlipColor(type);
}
}
_trackedBlips.Add(newBlip);
}
public void UnregisterTarget(Transform target)
{
for (int i = _trackedBlips.Count - 1; i >= 0; i--)
{
if (_trackedBlips[i].targetTransform == target)
{
if (_trackedBlips[i].iconInstance != null)
{
Destroy(_trackedBlips[i].iconInstance.gameObject);
}
_trackedBlips.RemoveAt(i);
}
}
}
private void UpdateRadarBlips()
{
Vector3 playerPos = playerTransform.position;
float playerYaw = playerTransform.eulerAngles.y;
for (int i = _trackedBlips.Count - 1; i >= 0; i--)
{
RadarBlip blip = _trackedBlips[i];
if (blip.targetTransform == null)
{
if (blip.iconInstance != null) Destroy(blip.iconInstance.gameObject);
_trackedBlips.RemoveAt(i);
continue;
}
// Vector from player to target in world coordinates
Vector3 diff = blip.targetTransform.position - playerPos;
Vector2 diff2D = new Vector2(diff.x, diff.z);
// Rotate relative to player heading if enabled
if (rotateWithPlayer)
{
diff2D = RotateVector2(diff2D, playerYaw);
}
float distance = diff2D.magnitude;
float normalizedDistance = Mathf.Clamp01(distance / radarWorldRadius);
Vector2 uiPos = diff2D.normalized * (normalizedDistance * radarUIRadius);
if (blip.iconInstance != null)
{
blip.iconInstance.rectTransform.anchoredPosition = uiPos;
// Clamp blip or hide if out of range
blip.iconInstance.gameObject.SetActive(distance <= radarWorldRadius * 1.2f);
}
}
}
private Vector2 RotateVector2(Vector2 v, float degrees)
{
float radians = degrees * Mathf.Deg2Rad;
float sin = Mathf.Sin(radians);
float cos = Mathf.Cos(radians);
return new Vector2(cos * v.x - sin * v.y, sin * v.x + cos * v.y);
}
private Color GetBlipColor(BlipType type)
{
switch (type)
{
case BlipType.Enemy: return enemyColor;
case BlipType.Friendly: return friendlyColor;
case BlipType.Objective: return objectiveColor;
case BlipType.Hazard: return hazardColor;
default: return Color.white;
}
}
}
}