/// /// MIT License - Copyright(c) 2019 Ugo Belfiore /// using UnityEngine; /// /// Create a Chrono, who start at 0, and increment over time. /// /// Use: create a new FrequencyChrono: /// private FrequencyChrono _chrono = new FrequencyChrono(); /// /// Start it when you want: /// _coolDown.StartChono(); /// /// You can give it a max time (it will go from 0 to 5, and stay at 5) /// _coolDown.StartChrono(5f); /// /// You can even ask it to loop: /// _coolDown.StartChrono(5f, true); /// /// at any time you want, get the current value of the Chrono: /// _coolDown.GetTimer(); /// /// if you want to test if the Chrono is currently running /// if (_coolDown.IsRunning()) /// /// if you have set a maxTime, and you want to test if the _coolDown is Started, and Finished: /// if (_coolDown.IsFinished()) /// /// Sometime it nice to know if the timer is not initialize, or finished, to start it again, you can do it with this: /// if (_coolDown.IsNotStartedOrFinished()) /// [System.Serializable] public class FrequencyChrono { private float _timeStart = 0; private bool _loop = false; private float _maxTime = -1; public float MaxTime { get { return (_maxTime); } set { _maxTime = value; } } private float _saveTime = 0; private bool _isInPause = false; public bool IsInPause { get { return (_isInPause); } } private bool _isFinishedOrNeverStarted = true; private bool _isStarted = false; public bool IsStarted { get { return (_isStarted); } } private bool _useUnscaleTime = false; private float _currentTime; #region public functions /// /// Start the Chrono /// /// define if we want to use a timeScale-independent timer or not public void StartChrono(bool useUnscaleTime = false) { _useUnscaleTime = useUnscaleTime; _timeStart = GetTimeScaledOrNot(); _loop = false; _isInPause = false; _maxTime = -1; _isFinishedOrNeverStarted = true; _isStarted = true; } /// /// Start the Chrono, with a maxTime. The chrono will stop at the max time, /// or loop if needed. /// /// max time in seconds /// do the chrono loop modulo maxTime ? /// define if we want to use a timeScale-independent timer or not public void StartChrono(float maxTime, bool loop, bool useUnscaleTime = false) { //if there is a negative maxTime, don't use it, and simply advance forward the timer without stopping if (maxTime < 0) { StartChrono(useUnscaleTime); return; } _useUnscaleTime = useUnscaleTime; _timeStart = GetTimeScaledOrNot(); _loop = loop; _maxTime = maxTime; _isInPause = false; _isFinishedOrNeverStarted = true; _isStarted = true; } /// /// return the current timer, in seconds /// eg: return 125.95 if the timer is at 2 minutes, 5 seconds and 95 miliseconds /// /// Should always be true, return the time when we were in pause /// return the time in seconds eg: return 125.95 if the timer is at 2 minutes, 5 seconds and 95 miliseconds public float GetTimer(bool managePause = true) { if (!_isStarted) { return (0); } if (managePause && _isInPause) { return (_saveTime); } _currentTime = GetTimeScaledOrNot() - _timeStart; if (_loop) { if (_currentTime > _maxTime) { _currentTime -= _maxTime; } _currentTime %= _maxTime; } else if (_maxTime != -1 && Mathf.Abs(_currentTime) > _maxTime) { _currentTime = _maxTime * Mathf.Sign(_currentTime); } return (_currentTime); } /// /// Is the Chrono started, but not finished yet ? /// if the Start options loop is set to false, and if the chrono is started, /// it will return true as long as you don't reset it. /// public bool IsRunning() { if (IsStarted && _isInPause) { return (true); } if (IsStarted && (!IsTimeExceedMaxTime() || _loop)) { return (true); } return (false); } /// /// Is the Chrono not started, or started and over ? /// /// public bool IsNotRunning() { return (!IsRunning()); } /// /// is the timer not started, or started and over, and not in pause /// /// return true if the chrono is not started, or started and over public bool IsNotStartedOrFinished() { if (!IsStarted) { return (true); } if (_isInPause) { return (false); } //if _maxTime is at 1, that mean we do'nt have any stop time, we will continue forever. if (_maxTime == -1) { return (false); } _currentTime = GetTimeScaledOrNot() - _timeStart; return (Mathf.Abs(_currentTime) >= _maxTime); } /// /// return true if the timer is finished (and reset the timer) /// /// if the parametter resetIfFinished si set to true, the chrono will /// reset if the coolDown is finished. That's mean if we test IsFinished() again, it will return false /// /// if the timer never started, return false; /// if the timer is in looping mode, return false; /// /// if true, the coolDown is reset. That's mean if we test IsFinished() again, it will return false /// public bool IsFinished(bool resetIfFinished = true) { if (_loop) { return (false); } if (!IsStarted) { return (false); } if (_maxTime == -1) { return (false); } if (IsTimeExceedMaxTime()) { if (resetIfFinished) { Reset(); } return (true); } //Debug.Log("ic not finished..."); return (false); } /// /// move in time forward manually by a certain amount /// /// jump time in second public void ManualForward(float jumpInTime = 0.016f) { _timeStart -= jumpInTime; _saveTime += jumpInTime; } /// /// move in time backward /// /// jump time in second public void ManualBackward(float jumpInTime = 0.016f) { _timeStart += jumpInTime; _saveTime -= jumpInTime; } /// /// set the Chrono to pause /// public void Pause() { if (_isInPause) { return; } _saveTime = GetTimer(false); _isInPause = true; } /// /// Resume the timer, assuming it was in pause previously. /// public void Resume() { if (!IsInPause) { return; } _isInPause = false; _timeStart = GetTimeScaledOrNot() - _saveTime; } /// /// reset the chrono to 0 & all the options /// public void Reset() { _timeStart = GetTimeScaledOrNot(); _loop = false; _isInPause = false; _isFinishedOrNeverStarted = true; _isStarted = false; } #endregion #region private functions /// /// get the current time, scaled or unscaled depending on the Start options /// Note if you don't have TimeEditor, you can use the normla Time of Unity /// /// return the current timer of unity private float GetTimeScaledOrNot() { return ((_useUnscaleTime) ? TimeEditor.unscaledTime : TimeEditor.time); } private bool IsTimeExceedMaxTime() { if (_maxTime < 0) { return (false); } return (Mathf.Abs(GetTimeScaledOrNot()) >= _timeStart + _maxTime); } #endregion }