using UnityEngine; using UnityEngine.UI; using TMPro; using UnityEngine.Events; using System; public class Timer : MonoBehaviour { public UnityEvent onTimerEnd; [Range(0, 23)] public int hours; [Range(0, 59)] public int minutes; [Range(0, 59)] public int seconds; public enum CountMethod { CountDown, CountUp }; public enum SeperatorType { Colon, Bullet, Slash }; public enum OutputType { None, StandardText, TMPro, HorizontalSlider, Dial }; [Tooltip("If checked, runs the timer on play")] public bool startAtRuntime = true; [Tooltip("Select what to display")] public bool hoursDisplay = false; public bool minutesDisplay = true; public bool secondsDisplay = true; [Space] [Tooltip("Select to count up or down")] public CountMethod countMethod; [Tooltip("Select the output type")] public OutputType outputType; public Text standardText; public TextMeshProUGUI textMeshProText; public Slider standardSlider; public Image dialSlider; bool timerRunning = false; bool timerPaused = false; public double timeRemaining; private void Awake() { if(!standardText) if(GetComponent()) { standardText = GetComponent(); } if(!textMeshProText) if(GetComponent()) { textMeshProText = GetComponent(); } if(!standardSlider) if(GetComponent()) { standardSlider = GetComponent(); } if(!dialSlider) if(GetComponent()) { dialSlider = GetComponent(); } if(standardSlider) { standardSlider.maxValue = ReturnTotalSeconds(); if(countMethod == CountMethod.CountDown) { standardSlider.value = standardSlider.maxValue; } else { standardSlider.value = standardSlider.minValue; } } if(dialSlider) { if (countMethod == CountMethod.CountDown) { dialSlider.fillAmount = 1f; } else { dialSlider.fillAmount = 0f; } } } void Start() { if(startAtRuntime) { StartTimer(); } else { if(countMethod == CountMethod.CountDown) { if(standardText) { standardText.text = DisplayFormattedTime(ReturnTotalSeconds()); } if(textMeshProText) { textMeshProText.text = DisplayFormattedTime(ReturnTotalSeconds()); } } else { if (standardText) { standardText.text = DisplayFormattedTime(0); } if (textMeshProText) { textMeshProText.text = DisplayFormattedTime(0); } } } } void Update() { if(timerRunning) { if(countMethod == CountMethod.CountDown) { CountDown(); if(standardSlider) { StandardSliderDown(); } if(dialSlider) { DialSliderDown(); } } else { CountUp(); if (standardSlider) { StandardSliderUp(); } if(dialSlider) { DialSliderUp(); } } } } private void CountDown() { /*If you choose to edit this back to 0 for 100% accuracy, 1 frame at the end of the timer will display maximum numbers as it takes time to switch to the else statement which sets the time remaining to 0. This is accurate up to 20 milliseconds or 0.02 of a second.*/ if (timeRemaining > 0.02) { timeRemaining -= Time.deltaTime; DisplayInTextObject(); } else { //Timer has ended from counting downwards timeRemaining = 0; timerRunning = false; if(onTimerEnd != null) { onTimerEnd.Invoke(); } DisplayInTextObject(); } } private void CountUp() { if (timeRemaining < ReturnTotalSeconds()) { timeRemaining += Time.deltaTime; DisplayInTextObject(); } else { //Timer has ended from counting upwards onTimerEnd.Invoke(); timeRemaining = ReturnTotalSeconds(); DisplayInTextObject(); timerRunning = false; } } private void StandardSliderDown() { if(standardSlider.value > standardSlider.minValue) { standardSlider.value -= Time.deltaTime; } } private void StandardSliderUp() { if (standardSlider.value < standardSlider.maxValue) { standardSlider.value += Time.deltaTime; } } private void DialSliderDown() { float timeRangeClamped = Mathf.InverseLerp(ReturnTotalSeconds(), 0, (float)timeRemaining); dialSlider.fillAmount = Mathf.Lerp(1, 0, timeRangeClamped); } private void DialSliderUp() { float timeRangeClamped = Mathf.InverseLerp(0, ReturnTotalSeconds(), (float)timeRemaining); dialSlider.fillAmount = Mathf.Lerp(0, 1, timeRangeClamped); } private void SetDialsAndSlidersValuesMidway() { if (standardSlider) { standardSlider.maxValue = ReturnTotalSeconds(); standardSlider.value = (float)timeRemaining; } if(dialSlider) { if(countMethod == CountMethod.CountDown) { DialSliderDown(); } else { DialSliderUp(); } } } private void DisplayInTextObject() { if (standardText) { standardText.text = DisplayFormattedTime(timeRemaining); } if (textMeshProText) { textMeshProText.text = DisplayFormattedTime(timeRemaining); } } public double GetRemainingSeconds() { return timeRemaining; } public void StartTimer(double timeToStartAt = 0) { if (!timerRunning && !timerPaused) { timerRunning = true; if (countMethod == CountMethod.CountDown) { timeRemaining = timeToStartAt; } else { timeRemaining = ReturnTotalSeconds() - timeToStartAt; SetDialsAndSlidersValuesMidway(); } } } public void StartTimerCustom(double timeToSet) { if(!timerRunning && !timerPaused) { timerRunning = true; } } public void StopTimer() { timerRunning = false; ResetTimer(); } private void ResetTimer() { timerPaused = false; if (countMethod == CountMethod.CountDown) { timeRemaining = ReturnTotalSeconds(); DisplayInTextObject(); if(standardSlider) { standardSlider.maxValue = ReturnTotalSeconds(); standardSlider.value = standardSlider.maxValue; } if(dialSlider) { dialSlider.fillAmount = 1f; } } else { timeRemaining = 0; DisplayInTextObject(); if (standardSlider) { standardSlider.maxValue = ReturnTotalSeconds(); standardSlider.value = standardSlider.minValue; } if (dialSlider) { dialSlider.fillAmount = 0f; } } } public float ReturnTotalSeconds() { float totalTimeSet; totalTimeSet = hours * 60 * 60; totalTimeSet += minutes * 60; totalTimeSet += seconds; return totalTimeSet; } public double ConvertToTotalSeconds(float hours, float minutes, float seconds) { timeRemaining = hours * 60 * 60; timeRemaining += minutes * 60; timeRemaining += seconds; DisplayFormattedTime(timeRemaining); return timeRemaining; } public string DisplayFormattedTime(double remainingSeconds) { string convertedNumber; float hours, minutes, seconds; RemainingSecondsToHHMMSSMMM(remainingSeconds, out hours, out minutes, out seconds); string HoursFormat() { if (hoursDisplay) { string hoursFormatted; hoursFormatted = string.Format("{0:00}", hours); if (minutesDisplay || secondsDisplay) hoursFormatted += ":"; return hoursFormatted; } return null; } string MinutesFormat() { if (minutesDisplay) { string minutesFormatted; minutesFormatted = string.Format("{0:00}", minutes); if (secondsDisplay) minutesFormatted += ":"; return minutesFormatted; } return null; } string SecondsFormat() { if (secondsDisplay) { string secondsFormatted; secondsFormatted = string.Format("{0:00}", seconds); return secondsFormatted; } return null; } convertedNumber = HoursFormat() + MinutesFormat() + SecondsFormat(); return convertedNumber; } private static void RemainingSecondsToHHMMSSMMM(double totalSeconds, out float hours, out float minutes, out float seconds) { hours = Mathf.FloorToInt((float)totalSeconds / 60 / 60); minutes = Mathf.FloorToInt(((float)totalSeconds / 60) - ((float)hours * 60)); seconds = Mathf.FloorToInt((float)totalSeconds - ((float)hours * 60 * 60) - ((float)minutes * 60)); } private void OnValidate() { //timeRemaining = ConvertToTotalSeconds(hours, minutes, seconds); } }