< Summary

Class:TacticalPanelController
Assembly:bamlab.micromissiles
File(s):/github/workspace/Assets/Scripts/UI/TacticalPanelController.cs
Covered lines:23
Uncovered lines:137
Coverable lines:160
Total lines:265
Line coverage:14.3% (23 of 160)
Covered branches:0
Total branches:0
Covered methods:7
Total methods:29
Method coverage:24.1% (7 of 29)

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity NPath complexity Sequence coverage
Awake()0%2.112070%
TacticalPanelController()0%110100%
Start()0%2100%
Update()0%2100%
OnDisable()0%110100%
InitializeController()0%2.312057.14%
SetupRadarUIGroup()0%2100%
ResetRadarUITransform()0%2100%
HandleRefreshTimer()0%6200%
UpdateSymbols()0%2100%
UpdateTrackSymbols[T](...)0%30500%
CreateSymbolPrefab()0%2100%
CreateOriginSymbol()0%2100%
CreateTrackSymbol(...)0%12300%
UpdateSymbolSpeedAlt(...)0%2100%
UpdateSymbolPosition(...)0%6200%
UpdateSymbolRotation(...)0%2100%
RemoveTrackSymbol(...)0%6200%
ClearAllSymbols()0%2.262060%
CycleRangeUp()0%2100%
CycleRangeDown()0%2100%
ZoomIn(...)0%2100%
ZoomOut(...)0%2100%
Pan(...)0%2100%
PanWithKeyboard(...)0%2100%
AdjustRadarScale(...)0%20400%
UpdateSymbolScale(...)0%2100%

File(s)

/github/workspace/Assets/Scripts/UI/TacticalPanelController.cs

#LineLine coverage
 1using UnityEngine;
 2using System.Collections.Generic;
 3using UnityEngine.UI;
 4using System.Linq;
 5
 6public class TacticalPanelController : MonoBehaviour {
 27  public static TacticalPanelController Instance { get; private set; }
 8
 19  private void Awake() {
 210    if (Instance == null) {
 111      Instance = this;
 112      InitializeController();
 113    } else {
 014      Destroy(gameObject);
 015    }
 116  }
 17
 18  [Tooltip("The UI group that contains the radar symbology elements")]
 19  [SerializeField]
 20  private GameObject _radarUIGroup;
 21
 22  [SerializeField]
 23  [Tooltip("How often to refresh symbol positions (in seconds)")]
 124  private float _refreshRate = 0.1f;
 25
 26  [SerializeField]
 127  private float _keyboardPanSpeed = 500f;  // Adjust this value in the inspector
 28
 29  [SerializeField]
 130  private float _panelZoomSpeed = 10.0f;
 31
 32  private RectTransform _radarUIGroupRectTransform;
 33  private IADS _iads;
 34  private float _timeSinceLastRefresh;
 135  private readonly Dictionary<TrackFileData, GameObject> _trackSymbols =
 36      new Dictionary<TrackFileData, GameObject>();
 37
 138  private List<GameObject> _originSymbols = new List<GameObject>();
 39
 40  private TacticalPolarGridGraphic _polarGridGraphic;
 41
 042  private void Start() {
 043    _iads = IADS.Instance;
 044    SetupRadarUIGroup();
 045    _timeSinceLastRefresh = 0f;
 046    CreateOriginSymbol();
 047  }
 48
 049  private void Update() {
 050    HandleRefreshTimer();
 051  }
 52
 153  private void OnDisable() {
 154    ClearAllSymbols();
 155  }
 56
 157  private void InitializeController() {
 58    // Initialize any controller-specific settings here if needed
 59    // Create polar grid
 160    _polarGridGraphic = _radarUIGroup.GetComponent<TacticalPolarGridGraphic>();
 161    if (_polarGridGraphic == null) {
 062      Debug.LogError("TacticalPolarGridGraphic not found on radar UI group");
 063    }
 164  }
 65
 066  private void SetupRadarUIGroup() {
 067    _radarUIGroupRectTransform = _radarUIGroup.GetComponent<RectTransform>();
 068    ResetRadarUITransform();
 069  }
 70
 071  private void ResetRadarUITransform() {
 072    _radarUIGroupRectTransform.localScale = Vector3.one;
 073    _radarUIGroupRectTransform.localPosition = Vector3.zero;
 074  }
 75
 076  private void HandleRefreshTimer() {
 077    _timeSinceLastRefresh += Time.unscaledDeltaTime;
 78
 079    if (_timeSinceLastRefresh >= _refreshRate) {
 080      UpdateSymbols();
 081      _timeSinceLastRefresh = 0f;
 082    }
 083  }
 84
 085  private void UpdateSymbols() {
 086    UpdateTrackSymbols(_iads.GetThreatTracks());
 087    UpdateTrackSymbols(_iads.GetInterceptorTracks());
 088  }
 89
 90  private void UpdateTrackSymbols<T>(List<T> currentTracks)
 091      where T : TrackFileData {
 92    // Remove inactive symbols
 093    var tracksToRemove =
 94        _trackSymbols.Keys.OfType<T>().Where(track => !currentTracks.Contains(track)).ToList();
 95
 096    foreach (var track in tracksToRemove) {
 097      RemoveTrackSymbol(track);
 098    }
 99
 100    // Update or create active symbols
 0101    foreach (var track in currentTracks) {
 0102      if (track.Status == TrackStatus.DESTROYED) {
 0103        RemoveTrackSymbol(track);
 0104        continue;
 105      }
 106
 0107      if (_trackSymbols.TryGetValue(track, out GameObject symbolObj)) {
 0108        UpdateSymbolPosition(symbolObj, track.Agent.transform.position);
 0109        UpdateSymbolScale(symbolObj);
 0110        UpdateSymbolRotation(symbolObj, track.Agent.transform.forward);
 0111        UpdateSymbolSpeedAlt(symbolObj.GetComponent<TacticalSymbol>(), track);
 0112      } else {
 0113        CreateTrackSymbol(track);
 0114      }
 0115    }
 0116  }
 117
 0118  private GameObject CreateSymbolPrefab() {
 0119    return Instantiate(Resources.Load<GameObject>("Prefabs/Symbols/SymbolPrefab"),
 120                       _radarUIGroupRectTransform);
 0121  }
 122
 0123  private void CreateOriginSymbol() {
 0124    GameObject symbolPrefab = CreateSymbolPrefab();
 0125    symbolPrefab.GetComponent<TacticalSymbol>().SetSprite("friendly_destroyer_present");
 0126    symbolPrefab.GetComponent<TacticalSymbol>().DisableDirectionArrow();
 0127    symbolPrefab.GetComponent<TacticalSymbol>().SetSpeedAlt("");
 0128    symbolPrefab.GetComponent<TacticalSymbol>().SetType("");
 0129    symbolPrefab.GetComponent<TacticalSymbol>().SetUniqueDesignator("");
 0130    _originSymbols.Add(symbolPrefab);
 0131  }
 132
 0133  private void CreateTrackSymbol(TrackFileData trackFile) {
 0134    GameObject symbolObj = CreateSymbolPrefab();
 0135    TacticalSymbol tacticalSymbol = symbolObj.GetComponent<TacticalSymbol>();
 136
 137    // Set common properties
 0138    tacticalSymbol.SetSprite(trackFile.Agent.staticAgentConfig.symbolPresent);
 0139    tacticalSymbol.SetDirectionArrowRotation(
 140        Mathf.Atan2(trackFile.Agent.GetVelocity().z, trackFile.Agent.GetVelocity().x) *
 141        Mathf.Rad2Deg);
 142
 0143    UpdateSymbolSpeedAlt(tacticalSymbol, trackFile);
 144
 145    // Set type-specific properties
 0146    if (trackFile is ThreatData) {
 0147      tacticalSymbol.SetType(trackFile.Agent.staticAgentConfig.agentClass.ToString());
 0148    } else if (trackFile is InterceptorData) {
 0149      tacticalSymbol.SetType("Interceptor");
 0150    }
 151
 0152    tacticalSymbol.SetUniqueDesignator(trackFile.TrackID);
 153
 0154    UpdateSymbolPosition(symbolObj, trackFile.Agent.transform.position);
 0155    UpdateSymbolRotation(symbolObj, trackFile.Agent.transform.forward);
 0156    UpdateSymbolScale(symbolObj);
 157
 0158    _trackSymbols.Add(trackFile, symbolObj);
 0159  }
 160
 0161  private void UpdateSymbolSpeedAlt(TacticalSymbol tacticalSymbol, TrackFileData trackFile) {
 0162    tacticalSymbol.SetSpeedAlt(
 163        $"{Utilities.ConvertMpsToKnots(trackFile.Agent.GetVelocity().magnitude):F0}kts/" +
 164        $"{Utilities.ConvertMetersToFeet(trackFile.Agent.transform.position.y):F0}ft");
 0165  }
 166
 167  /// <summary>
 168  /// Updates the position of a symbol based on the threat's real-world position.
 169  /// </summary>
 170  /// <param name="symbolObj">The symbol GameObject to update.</param>
 171  /// <param name="threatPosition">The real-world position of the threat.</param>
 0172  private void UpdateSymbolPosition(GameObject symbolObj, Vector3 threatPosition) {
 0173    if (_polarGridGraphic == null) {
 0174      Debug.LogError("TacticalPolarGridGraphic reference is missing.");
 0175      return;
 176    }
 177
 178    // Get the current scale factor from the grid
 0179    float scaleFactor = _polarGridGraphic.CurrentScaleFactor;
 180
 181    // Assuming threatPosition is in meters, convert to the grid's scale
 182    // Adjust the division factor as per your real-world scaling
 0183    float scaleDivisionFactor = 1000f;  // Example: 1000 meters = 1 unit on grid
 184
 0185    Vector3 scaledPosition = new Vector3(threatPosition.z / scaleDivisionFactor,
 186                                         threatPosition.x / scaleDivisionFactor, 0f);
 187
 188    // Apply the scaleFactor to ensure positioning aligns with grid scaling
 0189    symbolObj.transform.localPosition = scaledPosition * scaleFactor;
 0190  }
 191
 0192  private void UpdateSymbolRotation(GameObject symbolObj, Vector3 forward) {
 0193    symbolObj.GetComponent<TacticalSymbol>().SetDirectionArrowRotation(
 194        -1 * Mathf.Atan2(forward.z, forward.x) * Mathf.Rad2Deg);
 0195  }
 196
 0197  private void RemoveTrackSymbol(TrackFileData trackFile) {
 0198    if (_trackSymbols.TryGetValue(trackFile, out GameObject symbolObj)) {
 0199      Destroy(symbolObj);
 0200      _trackSymbols.Remove(trackFile);
 0201    }
 0202  }
 203
 1204  private void ClearAllSymbols() {
 3205    foreach (var symbol in _trackSymbols.Values) {
 0206      Destroy(symbol);
 0207    }
 1208    _trackSymbols.Clear();
 1209  }
 210
 0211  public void CycleRangeUp() {
 0212    _polarGridGraphic.CycleRangeUp();
 0213  }
 214
 0215  public void CycleRangeDown() {
 0216    _polarGridGraphic.CycleRangeDown();
 0217  }
 218
 0219  public void ZoomIn(float amount) {
 0220    AdjustRadarScale(amount * _panelZoomSpeed);
 0221  }
 222
 0223  public void ZoomOut(float amount) {
 0224    AdjustRadarScale(-amount * _panelZoomSpeed);
 0225  }
 226
 0227  public void Pan(Vector2 delta) {
 0228    Vector3 currentPos = _radarUIGroupRectTransform.localPosition;
 0229    _radarUIGroupRectTransform.localPosition =
 230        new Vector3(currentPos.x + delta.x, currentPos.y + delta.y, currentPos.z);
 0231  }
 232
 0233  public void PanWithKeyboard(Vector2 direction) {
 0234    Vector2 delta = direction * _keyboardPanSpeed * Time.unscaledDeltaTime;
 0235    Pan(delta);
 0236  }
 237
 238  /// <summary>
 239  /// Adjusts the radar scale by the specified amount.
 240  /// </summary>
 241  /// <param name="amount">The amount to adjust the radar scale.</param>
 0242  private void AdjustRadarScale(float amount) {
 0243    Vector3 newScale = _radarUIGroupRectTransform.localScale + new Vector3(amount, amount, 0f);
 244
 245    // Prevent negative or too small scaling
 0246    if (newScale.x < 0.01f || newScale.y < 0.01f) {
 0247      return;
 248    }
 249
 0250    _radarUIGroupRectTransform.localScale = newScale;
 251
 252    // Update all existing symbols' scales
 0253    foreach (var symbol in _trackSymbols.Values) {
 0254      UpdateSymbolScale(symbol);
 0255    }
 256    // Temporarily necessary until we implement IADS vessel system
 0257    UpdateSymbolScale(_originSymbols[0]);
 0258  }
 259
 0260  private void UpdateSymbolScale(GameObject symbolObj) {
 261    // Calculate inverse scale to maintain constant visual size
 0262    float inverseScale = 2f / _radarUIGroupRectTransform.localScale.x;
 0263    symbolObj.transform.localScale = new Vector3(inverseScale, inverseScale, 1f);
 0264  }
 265}