< Summary

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

Metrics

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

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 {
 1039  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")]
 113  private GameObject _cameraPanel = null!;
 14
 15  [SerializeField]
 16  [Tooltip("The UI panel that renders the tactical view for the TACTICAL mode")]
 117  private GameObject _tacticalPanel = null!;
 18
 19  [SerializeField]
 120  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;
 139  private int _numInterceptorHits = 0;
 140  private int _numInterceptorMisses = 0;
 141  private int _numInterceptorsRemaining = 0;
 142  private int _numThreatsRemaining = 0;
 43
 144  private UIMode _uiMode = UIMode.THREE_DIMENSIONAL;
 45
 46  public UIMode UIMode {
 6647    get => _uiMode;
 148    set {
 149      _uiMode = value;
 150      _cameraPanel.SetActive(_uiMode == UIMode.THREE_DIMENSIONAL);
 151      _tacticalPanel.SetActive(_uiMode == UIMode.TACTICAL);
 152    }
 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
 3566  public void LogAction(string message, Color color) {
 67    // Shift existing messages to older slots with faded colors.
 3568    pppppActionMessageTextHandle.text = ppppActionMessageTextHandle.text;
 3569    pppppActionMessageTextHandle.color =
 70        ppppActionMessageTextHandle.color * 0.8f;  // Fade color by 20%.
 71
 3572    ppppActionMessageTextHandle.text = ppActionMessageTextHandle.text;
 3573    ppppActionMessageTextHandle.color = ppActionMessageTextHandle.color * 0.85f;
 74
 3575    ppActionMessageTextHandle.text = pActionMessageTextHandle.text;
 3576    ppActionMessageTextHandle.color = pActionMessageTextHandle.color * 0.85f;
 77
 3578    pActionMessageTextHandle.text = actionMessageTextHandle.text;
 3579    pActionMessageTextHandle.color = actionMessageTextHandle.color * 0.9f;
 80
 81    // Set new message.
 3582    actionMessageTextHandle.text = message;
 3583    actionMessageTextHandle.color = color;
 3584  }
 85
 3586  public void LogActionMessage(string message) {
 3587    LogAction(message, Color.white);
 3588  }
 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
 198  private void Awake() {
 199    if (Instance != null && Instance != this) {
 0100      Destroy(gameObject);
 1101    } else {
 1102      Instance = this;
 1103    }
 1104  }
 105
 1106  private void Start() {
 1107    UIMode = UIMode.THREE_DIMENSIONAL;
 1108    _configSelectorPanel.SetActive(false);
 1109    SetupConfigSelectorPanel();
 1110    SimManager.Instance.OnNewInterceptor += RegisterNewInterceptor;
 1111    SimManager.Instance.OnNewThreat += RegisterNewThreat;
 1112    SimManager.Instance.OnSimulationEnded += RegisterSimulationEnded;
 1113    actionMessageTextHandle.text = "";
 1114    pActionMessageTextHandle.text = "";
 1115    ppActionMessageTextHandle.text = "";
 1116    ppppActionMessageTextHandle.text = "";
 1117    pppppActionMessageTextHandle.text = "";
 1118  }
 119
 33120  private void Update() {
 33121    UpdateSimTimeText();
 33122    UpdateTotalCostText();
 33123  }
 124
 1125  private void SetupConfigSelectorPanel() {
 1126    _configSelectorPanel.GetComponentInChildren<Button>().onClick.AddListener(
 0127        delegate { LoadSelectedConfig(); });
 1128    _configDropdown = _configSelectorPanel.GetComponentInChildren<TMP_Dropdown>();
 1129    PopulateConfigDropdown();
 1130  }
 131
 1132  private void PopulateConfigDropdown() {
 1133    _configDropdown.ClearOptions();
 1134    string configPath = ConfigLoader.GetStreamingAssetsFilePath("Configs/Simulations");
 1135    string[] configFiles = Directory.GetFiles(configPath, "*.pbtxt");
 136
 1137    List<string> configFileNames = new List<string>();
 39138    foreach (string configFile in configFiles) {
 12139      configFileNames.Add(Path.GetFileName(configFile));
 12140    }
 1141    _configDropdown.AddOptions(configFileNames);
 1142  }
 143
 0144  private void LoadSelectedConfig() {
 0145    string selectedConfig = _configDropdown.options[_configDropdown.value].text;
 0146    SimManager.Instance.LoadNewSimulationConfig(selectedConfig);
 0147    _configSelectorPanel.SetActive(false);
 0148  }
 149
 33150  private void UpdateSimTimeText() {
 33151    simTimeText.text = "Elapsed Time: " + SimManager.Instance.ElapsedTime.ToString("F2");
 33152    float expectedSimTimeAdvance = Time.unscaledDeltaTime * Time.timeScale;
 33153    float actualSimTimeAdvance = Time.deltaTime;
 154
 155    // Allow a small epsilon to account for floating-point precision errors.
 55156    if (actualSimTimeAdvance < expectedSimTimeAdvance - 0.001f) {
 22157      simTimeText.text += "\nThrottling time to meet physics rate";
 22158    }
 33159  }
 160
 33161  private void UpdateTotalCostText() {
 33162    double interceptorCost = SimManager.Instance.CostLaunchedInterceptors;
 33163    double threatCost = SimManager.Instance.CostDestroyedThreats;
 33164    double netCost = interceptorCost - threatCost;
 165
 33166    interceptorCostText.text = $"Interceptors\n(launched)\n${FormatCost(interceptorCost)}";
 33167    threatCostText.text = $"Threats\n(destroyed)\n${FormatCost(threatCost)}";
 33168    netCostText.text = $"Cost\ndifference\n${FormatCost(netCost)}";
 33169    if (netCost < 0) {
 0170      netCostText.color = Color.green;
 33171    } else {
 33172      netCostText.color = Color.red;
 33173    }
 33174  }
 175
 99176  private string FormatCost(double cost) {
 99177    double absCost = Math.Abs(cost);
 99178    if (absCost >= 1e9)
 0179      return $"{cost / 1e9:F2}B";
 99180    if (absCost >= 1e6)
 0181      return $"{cost / 1e6:F2}M";
 99182    if (absCost >= 1e3)
 0183      return $"{cost / 1e3:F2}k";
 99184    return $"{cost:F2}";
 99185  }
 186
 980187  private void UpdateSummaryText() {
 980188    interceptorRemainingTextHandle.text = _numInterceptorsRemaining.ToString();
 980189    threatRemainingTextHandle.text = _numThreatsRemaining.ToString();
 980190    interceptorHitTextHandle.text = _numInterceptorHits.ToString();
 980191    interceptorMissTextHandle.text = _numInterceptorMisses.ToString();
 980192  }
 193
 14194  private void RegisterNewInterceptor(IInterceptor interceptor) {
 14195    ++_numInterceptorsRemaining;
 14196    interceptor.OnHit += RegisterInterceptorHit;
 14197    interceptor.OnMiss += RegisterInterceptorMiss;
 14198    interceptor.OnTerminated += RegisterAgentTerminated;
 14199    UpdateSummaryText();
 14200  }
 201
 955202  private void RegisterNewThreat(IThreat threat) {
 955203    ++_numThreatsRemaining;
 955204    threat.OnTerminated += RegisterAgentTerminated;
 955205    UpdateSummaryText();
 955206  }
 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
 11227  private void RegisterSimulationEnded() {
 11228    _numInterceptorsRemaining = 0;
 11229    _numThreatsRemaining = 0;
 11230    _numInterceptorHits = 0;
 11231    _numInterceptorMisses = 0;
 11232    UpdateSummaryText();
 11233  }
 234}