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