< Summary

Class:UIManager
Assembly:bamlab.micromissiles
File(s):/github/workspace/Assets/Scripts/UI/UIManager.cs
Covered lines:0
Uncovered lines:162
Coverable lines:162
Total lines:234
Line coverage:0% (0 of 162)
Covered branches:0
Total branches:0
Covered methods:0
Total methods:27
Method coverage:0% (0 of 27)

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity NPath complexity Sequence coverage
UIManager()0%2100%
ToggleUIMode()0%2100%
ToggleConfigSelectorPanel()0%2100%
LogAction(...)0%2100%
LogActionMessage(...)0%2100%
LogActionWarning(...)0%2100%
LogActionError(...)0%2100%
Awake()0%12300%
Start()0%2100%
Update()0%2100%
SetupConfigSelectorPanel()0%2100%
PopulateConfigDropdown()0%6200%
LoadSelectedConfig()0%2100%
UpdateSimTimeText()0%6200%
UpdateTotalCostText()0%6200%
FormatCost(...)0%20400%
UpdateSummaryText()0%2100%
RegisterNewInterceptor(...)0%2100%
RegisterNewThreat(...)0%2100%
RegisterInterceptorHit(...)0%2100%
RegisterInterceptorMiss(...)0%2100%
RegisterAgentTerminated(...)0%12300%
RegisterSimulationEnded()0%2100%

File(s)

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

#LineLine coverage
 1using System;
 2using System.Collections.Generic;
 3using System.IO;
 4using TMPro;
 5using UnityEngine;
 6using UnityEngine.UI;
 7
 8public class UIManager : MonoBehaviour {
 09  public static UIManager Instance { get; private set; }
 10
 11  [SerializeField]
 12  [Tooltip("The UI panel that renders the camera view for the THREE_DIMENSIONAL mode")]
 013  private GameObject _cameraPanel = null!;
 14
 15  [SerializeField]
 16  [Tooltip("The UI panel that renders the tactical view for the TACTICAL mode")]
 017  private GameObject _tacticalPanel = null!;
 18
 19  [SerializeField]
 020  private GameObject _configSelectorPanel = null!;
 21  private TMP_Dropdown _configDropdown;
 22  public TextMeshProUGUI simTimeText;
 23  public TextMeshProUGUI interceptorCostText;
 24  public TextMeshProUGUI threatCostText;
 25  public TextMeshProUGUI netCostText;
 26
 27  public TextMeshProUGUI interceptorHitTextHandle;
 28  public TextMeshProUGUI interceptorMissTextHandle;
 29  public TextMeshProUGUI interceptorRemainingTextHandle;
 30  public TextMeshProUGUI threatRemainingTextHandle;
 31
 32  public TextMeshProUGUI actionMessageTextHandle;
 33  public TextMeshProUGUI pActionMessageTextHandle;
 34  public TextMeshProUGUI ppActionMessageTextHandle;
 35  public TextMeshProUGUI ppppActionMessageTextHandle;
 36  public TextMeshProUGUI pppppActionMessageTextHandle;
 37
 38  public TMP_FontAsset GlobalFont;
 039  private int _numInterceptorHits = 0;
 040  private int _numInterceptorMisses = 0;
 041  private int _numInterceptorsRemaining = 0;
 042  private int _numThreatsRemaining = 0;
 43
 044  private UIMode _uiMode = UIMode.THREE_DIMENSIONAL;
 45
 46  public UIMode UIMode {
 047    get => _uiMode;
 048    set {
 049      _uiMode = value;
 050      _cameraPanel.SetActive(_uiMode == UIMode.THREE_DIMENSIONAL);
 051      _tacticalPanel.SetActive(_uiMode == UIMode.TACTICAL);
 052    }
 53  }
 54
 055  public void ToggleUIMode() {
 056    Array uiModeValues = Enum.GetValues(typeof(UIMode));
 057    int currentIndex = Array.IndexOf(uiModeValues, UIMode);
 058    int nextIndex = (currentIndex + 1) % uiModeValues.Length;
 059    UIMode = (UIMode)uiModeValues.GetValue(nextIndex);
 060  }
 61
 062  public void ToggleConfigSelectorPanel() {
 063    _configSelectorPanel.SetActive(!_configSelectorPanel.activeSelf);
 064  }
 65
 066  public void LogAction(string message, Color color) {
 67    // Shift existing messages to older slots with faded colors.
 068    pppppActionMessageTextHandle.text = ppppActionMessageTextHandle.text;
 069    pppppActionMessageTextHandle.color =
 70        ppppActionMessageTextHandle.color * 0.8f;  // Fade color by 20%.
 71
 072    ppppActionMessageTextHandle.text = ppActionMessageTextHandle.text;
 073    ppppActionMessageTextHandle.color = ppActionMessageTextHandle.color * 0.85f;
 74
 075    ppActionMessageTextHandle.text = pActionMessageTextHandle.text;
 076    ppActionMessageTextHandle.color = pActionMessageTextHandle.color * 0.85f;
 77
 078    pActionMessageTextHandle.text = actionMessageTextHandle.text;
 079    pActionMessageTextHandle.color = actionMessageTextHandle.color * 0.9f;
 80
 81    // Set new message.
 082    actionMessageTextHandle.text = message;
 083    actionMessageTextHandle.color = color;
 084  }
 85
 086  public void LogActionMessage(string message) {
 087    LogAction(message, Color.white);
 088  }
 89
 090  public void LogActionWarning(string message) {
 091    LogAction(message, Color.yellow);
 092  }
 93
 094  public void LogActionError(string message) {
 095    LogAction(message, Color.red);
 096  }
 97
 098  private void Awake() {
 099    if (Instance != null && Instance != this) {
 0100      Destroy(gameObject);
 0101    } else {
 0102      Instance = this;
 0103    }
 0104  }
 105
 0106  private void Start() {
 0107    UIMode = UIMode.THREE_DIMENSIONAL;
 0108    _configSelectorPanel.SetActive(false);
 0109    SetupConfigSelectorPanel();
 0110    SimManager.Instance.OnNewInterceptor += RegisterNewInterceptor;
 0111    SimManager.Instance.OnNewThreat += RegisterNewThreat;
 0112    SimManager.Instance.OnSimulationEnded += RegisterSimulationEnded;
 0113    actionMessageTextHandle.text = "";
 0114    pActionMessageTextHandle.text = "";
 0115    ppActionMessageTextHandle.text = "";
 0116    ppppActionMessageTextHandle.text = "";
 0117    pppppActionMessageTextHandle.text = "";
 0118  }
 119
 0120  private void Update() {
 0121    UpdateSimTimeText();
 0122    UpdateTotalCostText();
 0123  }
 124
 0125  private void SetupConfigSelectorPanel() {
 0126    _configSelectorPanel.GetComponentInChildren<Button>().onClick.AddListener(
 0127        delegate { LoadSelectedConfig(); });
 0128    _configDropdown = _configSelectorPanel.GetComponentInChildren<TMP_Dropdown>();
 0129    PopulateConfigDropdown();
 0130  }
 131
 0132  private void PopulateConfigDropdown() {
 0133    _configDropdown.ClearOptions();
 0134    string configPath = ConfigLoader.GetStreamingAssetsFilePath("Configs/Simulations");
 0135    string[] configFiles = Directory.GetFiles(configPath, "*.pbtxt");
 136
 0137    List<string> configFileNames = new List<string>();
 0138    foreach (string configFile in configFiles) {
 0139      configFileNames.Add(Path.GetFileName(configFile));
 0140    }
 0141    _configDropdown.AddOptions(configFileNames);
 0142  }
 143
 0144  private void LoadSelectedConfig() {
 0145    string selectedConfig = _configDropdown.options[_configDropdown.value].text;
 0146    SimManager.Instance.LoadNewSimulationConfig(selectedConfig);
 0147    _configSelectorPanel.SetActive(false);
 0148  }
 149
 0150  private void UpdateSimTimeText() {
 0151    simTimeText.text = "Elapsed Time: " + SimManager.Instance.ElapsedTime.ToString("F2");
 0152    float expectedSimTimeAdvance = Time.unscaledDeltaTime * Time.timeScale;
 0153    float actualSimTimeAdvance = Time.deltaTime;
 154
 155    // Allow a small epsilon to account for floating-point precision errors.
 0156    if (actualSimTimeAdvance < expectedSimTimeAdvance - 0.001f) {
 0157      simTimeText.text += "\nThrottling time to meet physics rate";
 0158    }
 0159  }
 160
 0161  private void UpdateTotalCostText() {
 0162    double interceptorCost = SimManager.Instance.CostLaunchedInterceptors;
 0163    double threatCost = SimManager.Instance.CostDestroyedThreats;
 0164    double netCost = interceptorCost - threatCost;
 165
 0166    interceptorCostText.text = $"Interceptors\n(launched)\n${FormatCost(interceptorCost)}";
 0167    threatCostText.text = $"Threats\n(destroyed)\n${FormatCost(threatCost)}";
 0168    netCostText.text = $"Cost\ndifference\n${FormatCost(netCost)}";
 0169    if (netCost < 0) {
 0170      netCostText.color = Color.green;
 0171    } else {
 0172      netCostText.color = Color.red;
 0173    }
 0174  }
 175
 0176  private string FormatCost(double cost) {
 0177    double absCost = Math.Abs(cost);
 0178    if (absCost >= 1e9)
 0179      return $"{cost / 1e9:F2}B";
 0180    if (absCost >= 1e6)
 0181      return $"{cost / 1e6:F2}M";
 0182    if (absCost >= 1e3)
 0183      return $"{cost / 1e3:F2}k";
 0184    return $"{cost:F2}";
 0185  }
 186
 0187  private void UpdateSummaryText() {
 0188    interceptorRemainingTextHandle.text = _numInterceptorsRemaining.ToString();
 0189    threatRemainingTextHandle.text = _numThreatsRemaining.ToString();
 0190    interceptorHitTextHandle.text = _numInterceptorHits.ToString();
 0191    interceptorMissTextHandle.text = _numInterceptorMisses.ToString();
 0192  }
 193
 0194  private void RegisterNewInterceptor(IInterceptor interceptor) {
 0195    ++_numInterceptorsRemaining;
 0196    interceptor.OnHit += RegisterInterceptorHit;
 0197    interceptor.OnMiss += RegisterInterceptorMiss;
 0198    interceptor.OnTerminated += RegisterAgentTerminated;
 0199    UpdateSummaryText();
 0200  }
 201
 0202  private void RegisterNewThreat(IThreat threat) {
 0203    ++_numThreatsRemaining;
 0204    threat.OnTerminated += RegisterAgentTerminated;
 0205    UpdateSummaryText();
 0206  }
 207
 0208  private void RegisterInterceptorHit(IInterceptor interceptor) {
 0209    ++_numInterceptorHits;
 0210    UpdateSummaryText();
 0211  }
 212
 0213  private void RegisterInterceptorMiss(IInterceptor interceptor) {
 0214    ++_numInterceptorMisses;
 0215    UpdateSummaryText();
 0216  }
 217
 0218  private void RegisterAgentTerminated(IAgent agent) {
 0219    if (agent is IInterceptor) {
 0220      --_numInterceptorsRemaining;
 0221    } else if (agent is IThreat) {
 0222      --_numThreatsRemaining;
 0223    }
 0224    UpdateSummaryText();
 0225  }
 226
 0227  private void RegisterSimulationEnded() {
 0228    _numInterceptorsRemaining = 0;
 0229    _numThreatsRemaining = 0;
 0230    _numInterceptorHits = 0;
 0231    _numInterceptorMisses = 0;
 0232    UpdateSummaryText();
 0233  }
 234}