using System; using System.Collections.Generic; using TMPro; using UnityEngine; using UnityEngine.SceneManagement; using UnityEngine.UI; public class GameOverlay : MonoBehaviour, IDDataPersistence { public static GameOverlay Instance { get; private set; } [Header("Canvas Attributes")] [SerializeField] TextMeshProUGUI levelTitleText; // Reference to the title of the level text [SerializeField] Image timerImage; // Reference to the timer that ticks down for the time trial [SerializeField] Image completedTrialImage; // Reference for the medal Image [SerializeField] TextMeshProUGUI timeToCompleteTrial; // Reference to how much time is left for the trial to be completed [SerializeField] bool hasDollyCamera = true; // Reference for if the current level has a dolly camera, if so the start timer won't start automatically, otherwise will start // Reference bool trialCompleted = false; // Reference to be called upon loading and saving if the image for the medal is activated bool startTimer = false; // Reference for the trigger to start the timer to make sure when the level is fully ready to start // Components LevelSO[] levelRefs; // Reference for the collection of levels for the Game Overlay script to cycle through LevelSO levelRef; // Reference for the Level SO for the current Level float timer; // Time to tick down bool paused; /// <summary> /// Starts the game overlay's timer /// </summary> public void StartTimer() => startTimer = true; void Awake() { Instance = this; } // Start is called before the first frame update void Start() { try { LoadData(DataPersistenceManager.Instance.gameData); } catch (NullReferenceException ex) when (DataPersistenceManager.Instance.gameData == null) { throw new NullReferenceException("Game Data not initialized, loading overlay data has failed! Continuing as if level has not been completed...", ex); } timerImage.fillAmount = 1f; // Sets the timer image state to full amount timeToCompleteTrial.text = levelRef.levelTimeTrial.ToString(); // Sets the text inside the timer for the time to complete the trial from the level reference timer = levelRef.levelTimeTrial; // Sets the time for the trial to be completed levelTitleText.text = levelRef.levelName; // Level title is set to the name of the current Level SO name // If the reference for the trial have already been completed returns true then the medal image show up next to the timer // otherwise it does not show up if (trialCompleted) completedTrialImage.enabled = true; else completedTrialImage.enabled = false; if (!hasDollyCamera) StartTimer(); } // Update is called once per frame void Update() { if (!MainMenu.IsPaused && startTimer) TimeTrialTimer(); } /// <summary> /// Timer for the Time Trial that will continously tick down if the timer value is positive /// </summary> void TimeTrialTimer() { // When the timer is positive it will continously count down based on delta time and decrement the timer image if (timer > 0f && !paused) { timer -= Time.deltaTime; timerImage.fillAmount = timer / levelRef.levelTimeTrial; timeToCompleteTrial.text = Mathf.CeilToInt(timer).ToString(); } // This else if statement makes sure that the fill amount will always end up at zero if the timer value doesn't properly align with the fill amount else if (timer <= 0f && timerImage.fillAmount > 0f) { timerImage.fillAmount = 0f; timeToCompleteTrial.text = "0"; } } public bool StopTimer() { bool output = false; if (timer > 0f) { paused = true; trialCompleted = true; completedTrialImage.enabled = true; output = true; } SaveData(ref DataPersistenceManager.Instance.gameData); return output; } public void LoadData(GameData data) { levelRefs = Resources.LoadAll<LevelSO>("Levels/"); foreach (KeyValuePair<string, bool> levelName in data.completedTrials) { if (levelName.Key == SceneManager.GetActiveScene().name) { for (int i = 0; i < levelRefs.Length; i++) { if (levelRefs[i].levelName == levelName.Key) { levelRef = levelRefs[i]; break; } } trialCompleted = levelName.Value; break; } } } public void SaveData(ref GameData data) { data.completedTrials.Remove(levelRef.levelName); // Removes the level reference data.levelTimesCompleted.Remove(levelRef.levelName); // Removes the level reference for the time aspect data.completedTrials.Add(levelRef.levelName, trialCompleted); // Then re-adds the level with the current trial state data.levelTimesCompleted.Add(levelRef.levelName, timer); // Then re-adds the level with the time that is left for the current level } }