using Core; using Core.Lifecycle; using TMPro; using UnityEngine; using UnityEngine.UI; namespace Minigames.Airplane.UI { /// /// Displays target information: icon and distance remaining to target. /// Updates in real-time as the airplane moves. /// public class TargetDisplayUI : ManagedBehaviour { #region Inspector References [Header("UI Elements")] [Tooltip("Image to display target icon")] [SerializeField] private Image targetIcon; [Tooltip("Text to display distance remaining")] [SerializeField] private TextMeshProUGUI distanceText; [Header("Display Settings")] [Tooltip("Format string for distance display (e.g., '{0:F1}m')")] [SerializeField] private string distanceFormat = "{0:F1}m"; [Tooltip("Update distance every N frames (0 = every frame)")] [SerializeField] private int updateInterval = 5; [Header("Debug")] [SerializeField] private bool showDebugLogs; #endregion #region State private Transform _planeTransform; private Transform _launchPointTransform; private Vector3 _targetPosition; private bool _isActive; private int _frameCounter; #endregion #region Lifecycle internal override void OnManagedAwake() { base.OnManagedAwake(); // Hide by default Hide(); // Validate references if (targetIcon == null) { Logging.Warning("[TargetDisplayUI] Target icon image not assigned!"); } if (distanceText == null) { Logging.Warning("[TargetDisplayUI] Distance text not assigned!"); } } private void Update() { if (!_isActive || _planeTransform == null) return; // Update distance at specified interval _frameCounter++; if (updateInterval == 0 || _frameCounter >= updateInterval) { _frameCounter = 0; UpdateDistance(); } } #endregion #region Public API /// /// Setup the target display with icon and target position. /// /// Sprite to display as target icon /// World position of the target /// Launch point transform (used for distance when plane not available) public void Setup(Sprite targetSprite, Vector3 targetPosition, Transform launchPoint) { _targetPosition = targetPosition; _launchPointTransform = launchPoint; // Set icon if (targetIcon != null && targetSprite != null) { targetIcon.sprite = targetSprite; targetIcon.enabled = true; } // Update distance immediately using launch point UpdateDistance(); if (showDebugLogs) { Logging.Debug($"[TargetDisplayUI] Setup with target at {targetPosition}"); } } /// /// Start tracking the airplane and updating distance. /// Note: Does not automatically show UI - call Show() separately. /// /// Transform of the airplane to track public void StartTracking(Transform planeTransform) { _planeTransform = planeTransform; _isActive = true; _frameCounter = 0; // Update distance immediately if visible if (gameObject.activeSelf) { UpdateDistance(); } if (showDebugLogs) { Logging.Debug("[TargetDisplayUI] Started tracking airplane"); } } /// /// Stop tracking the airplane. /// Note: Does not automatically hide UI - call Hide() separately. /// public void StopTracking() { _isActive = false; _planeTransform = null; if (showDebugLogs) { Logging.Debug("[TargetDisplayUI] Stopped tracking"); } } /// /// Show the UI. /// public void Show() { gameObject.SetActive(true); } /// /// Hide the UI. /// public void Hide() { gameObject.SetActive(false); } #endregion #region Internal /// /// Update the distance text based on current plane position. /// Uses launch point if plane isn't available yet. /// private void UpdateDistance() { if (distanceText == null) return; // Use plane position if available, otherwise use launch point Vector3 currentPosition; if (_planeTransform != null) { currentPosition = _planeTransform.position; } else if (_launchPointTransform != null) { currentPosition = _launchPointTransform.position; } else { // No reference available return; } // Calculate horizontal distance (X-axis only for side-scroller) float distance = Mathf.Abs(_targetPosition.x - currentPosition.x); // Update text distanceText.text = string.Format(distanceFormat, distance); } /// /// Update distance and ensure UI is shown. /// Call when showing UI to refresh distance display. /// public void UpdateAndShow() { UpdateDistance(); Show(); } #endregion } }