├── .gitignore ├── Example.meta ├── Example ├── TestTimerBehaviour.cs ├── TestTimerBehaviour.cs.meta ├── TimerExampleScene.unity └── TimerExampleScene.unity.meta ├── LICENSE ├── README.md ├── Source.meta └── Source ├── DelayFrameTimer.cs ├── DelayFrameTimer.cs.meta ├── DelayTimer.cs ├── DelayTimer.cs.meta ├── LoopCountTimer.cs ├── LoopCountTimer.cs.meta ├── LoopTimer.cs ├── LoopTimer.cs.meta ├── LoopUntilTimer.cs ├── LoopUntilTimer.cs.meta ├── Timer.cs ├── Timer.cs.meta ├── TimerExtensions.cs └── TimerExtensions.cs.meta /.gitignore: -------------------------------------------------------------------------------- 1 | # This .gitignore file should be placed at the root of your Unity project directory 2 | # 3 | # Get latest from https://github.com/github/gitignore/blob/master/Unity.gitignore 4 | # 5 | /[Ll]ibrary/ 6 | /[Tt]emp/ 7 | /[Oo]bj/ 8 | /[Bb]uild/ 9 | /[Bb]uilds/ 10 | /[Ll]ogs/ 11 | /[Mm]emoryCaptures/ 12 | 13 | # Asset meta data should only be ignored when the corresponding asset is also ignored 14 | !/[Aa]ssets/**/*.meta 15 | 16 | # Uncomment this line if you wish to ignore the asset store tools plugin 17 | # /[Aa]ssets/AssetStoreTools* 18 | 19 | # Autogenerated Jetbrains Rider plugin 20 | [Aa]ssets/Plugins/Editor/JetBrains* 21 | 22 | # Visual Studio cache directory 23 | .vs/ 24 | 25 | # Gradle cache directory 26 | .gradle/ 27 | 28 | # Autogenerated VS/MD/Consulo solution and project files 29 | ExportedObj/ 30 | .consulo/ 31 | *.csproj 32 | *.unityproj 33 | *.sln 34 | *.suo 35 | *.tmp 36 | *.user 37 | *.userprefs 38 | *.pidb 39 | *.booproj 40 | *.svd 41 | *.pdb 42 | *.mdb 43 | *.opendb 44 | *.VC.db 45 | 46 | # Unity3D generated meta files 47 | *.pidb.meta 48 | *.pdb.meta 49 | *.mdb.meta 50 | 51 | README.md.meta 52 | LICENSE.meta 53 | 54 | # Unity3D generated file on crash reports 55 | sysinfo.txt 56 | 57 | # Builds 58 | *.apk 59 | *.unitypackage 60 | 61 | # Crashlytics generated file 62 | crashlytics-build.properties 63 | 64 | -------------------------------------------------------------------------------- /Example.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 7acf3a204a87548898eeecad818ae3a8 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Example/TestTimerBehaviour.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using GameUtil; 3 | using UnityEngine; 4 | using UnityEngine.UI; 5 | 6 | namespace UnityTimer.Examples 7 | { 8 | public class TestTimerBehaviour : MonoBehaviour 9 | { 10 | #region Unity Inspector Fields 11 | 12 | [Header("Controls")] 13 | public InputField DurationField; 14 | public InputField LoopCountField; 15 | 16 | public Button StartTimerButton; 17 | public Button CancelTimerButton; 18 | public Button PauseTimerButton; 19 | public Button ResumeTimerButton; 20 | public Button RestartTimerButton; 21 | 22 | public Toggle IsLoopedToggle; 23 | public Toggle UseGameTimeToggle; 24 | 25 | public Slider TimescaleSlider; 26 | 27 | public Text NeedsRestartText; 28 | 29 | [Header("Stats Texts")] public Text TimeElapsedText; 30 | public Text TimeRemainingText; 31 | public Text PercentageCompletedText; 32 | public Text PercentageRemainingText; 33 | 34 | public Text NumberOfLoopsText; 35 | public Text IsCancelledText; 36 | public Text IsCompletedText; 37 | public Text IsPausedText; 38 | public Text IsDoneText; 39 | public Text UpdateText; 40 | 41 | #endregion 42 | 43 | private int _numLoops; 44 | private Timer _testTimer; 45 | 46 | private void Awake() 47 | { 48 | RestartTimerButton.interactable = false; 49 | IsLoopedToggle.onValueChanged.AddListener(OnLoopToggleChanged); 50 | OnLoopToggleChanged(IsLoopedToggle.isOn); 51 | ResetState(); 52 | } 53 | 54 | private void ResetState() 55 | { 56 | _numLoops = 0; 57 | CancelTestTimer(); 58 | } 59 | 60 | public void StartTestTimer() 61 | { 62 | ResetState(); 63 | 64 | // this is the important code example bit where we register a new timer 65 | if (IsLoopedToggle.isOn) 66 | { 67 | int loopCount = GetLoopCount(); 68 | if (loopCount >= 0) 69 | _testTimer = this.LoopCountAction(GetDurationValue(), loopCount, loopTime => _numLoops = loopTime, 70 | secondsElapsed => { UpdateText.text = string.Format("Timer ran update callback: {0:F2} seconds", secondsElapsed); }, 71 | () => { UpdateText.text = string.Format("LoopCountTimer finished! LoopTimes:{0}", ((LoopTimer) _testTimer)?.loopTimes ?? 0); }, 72 | !UseGameTimeToggle.isOn); 73 | else 74 | _testTimer = this.LoopAction(GetDurationValue(), loopTime => _numLoops = loopTime, 75 | secondsElapsed => { UpdateText.text = string.Format("Timer ran update callback: {0:F2} seconds", secondsElapsed); }, 76 | !UseGameTimeToggle.isOn); 77 | } 78 | else 79 | _testTimer = this.DelayAction(GetDurationValue(), () => _numLoops++, 80 | secondsElapsed => 81 | { 82 | UpdateText.text = string.Format("Timer ran update callback: {0:F2} seconds", secondsElapsed); 83 | }, !UseGameTimeToggle.isOn); 84 | CancelTimerButton.interactable = true; 85 | RestartTimerButton.interactable = true; 86 | } 87 | 88 | public void CancelTestTimer() 89 | { 90 | Timer.Cancel(_testTimer); 91 | CancelTimerButton.interactable = false; 92 | NeedsRestartText.gameObject.SetActive(false); 93 | } 94 | 95 | public void PauseTestTimer() 96 | { 97 | Timer.Pause(_testTimer); 98 | } 99 | 100 | public void ResumeTestTimer() 101 | { 102 | Timer.Resume(_testTimer); 103 | } 104 | 105 | public void RestartTimer() 106 | { 107 | Timer.Restart(_testTimer); 108 | CancelTimerButton.interactable = true; 109 | } 110 | 111 | private void Update() 112 | { 113 | NumberOfLoopsText.text = string.Format("# Loops: {0}", _numLoops); 114 | if (_testTimer == null) 115 | { 116 | return; 117 | } 118 | 119 | Time.timeScale = TimescaleSlider.value; 120 | 121 | TimeElapsedText.text = string.Format("Time elapsed: {0:F2} seconds", _testTimer.GetTimeElapsed()); 122 | TimeRemainingText.text = string.Format("Time remaining: {0:F2} seconds", _testTimer.GetTimeRemaining()); 123 | PercentageCompletedText.text = string.Format("Percentage completed: {0:F4}%", 124 | _testTimer.GetRatioComplete()*100); 125 | PercentageRemainingText.text = String.Format("Percentage remaining: {0:F4}%", 126 | _testTimer.GetRatioRemaining()*100); 127 | IsCancelledText.text = string.Format("Is Cancelled: {0}", _testTimer.isCancelled); 128 | IsCompletedText.text = string.Format("Is Completed: {0}", _testTimer.isCompleted); 129 | IsPausedText.text = String.Format("Is Paused: {0}", _testTimer.isPaused); 130 | IsDoneText.text = string.Format("Is Done: {0}", _testTimer.isDone); 131 | 132 | PauseTimerButton.interactable = !_testTimer.isPaused; 133 | ResumeTimerButton.interactable = _testTimer.isPaused; 134 | 135 | NeedsRestartText.gameObject.SetActive(ShouldShowRestartText()); 136 | } 137 | 138 | private bool ShouldShowRestartText() 139 | { 140 | var timerType = _testTimer.GetType(); 141 | return IsLoopedToggle.isOn != typeof(LoopTimer).IsAssignableFrom(timerType) || // we switched timer type or 142 | UseGameTimeToggle.isOn == _testTimer.usesRealTime || // we switched usesRealTime or 143 | Mathf.Abs(GetDurationValue() - _testTimer.duration) >= Mathf.Epsilon; // our duration changed 144 | } 145 | 146 | private float GetDurationValue() 147 | { 148 | float duration; 149 | return float.TryParse(DurationField.text, out duration) ? duration : 0; 150 | } 151 | 152 | private int GetLoopCount() 153 | { 154 | int loopCount; 155 | return int.TryParse(LoopCountField.text, out loopCount) ? loopCount : 0; 156 | } 157 | 158 | private void OnLoopToggleChanged(bool isOn) 159 | { 160 | LoopCountField.transform.parent.gameObject.SetActive(isOn); 161 | } 162 | } 163 | } -------------------------------------------------------------------------------- /Example/TestTimerBehaviour.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 994bff44e24df45efbfb6d196febb5b5 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Example/TimerExampleScene.unity.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 86fbdfb9d7e5c4336a74fcc892aabb3e 3 | DefaultImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 GH-ZJ 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Unity Timer 2 | 3 | Run actions after a delay in Unity3D. 4 | 5 | This library has been battle-tested and hardened throughout numerous projects, including the award-winning [Pitfall Planet](http://pitfallplanet.com/). 6 | 7 | Written by [Alexander Biggs](http://akbiggs.com) + [Adam Robinson-Yu](http://www.adamgryu.com/). 8 | 9 | Fork by GH-ZJ(wustzhangjie@gmail.com) 10 | 11 | ## Basic Example 12 | 13 | The Unity Timer package provides the following method for creating timers: 14 | ```c# 15 | public static DelayTimer DelayAction(float duration, Action onComplete, Action onUpdate = null, bool useRealTime = false, Object autoDestroyOwner = null); 16 | 17 | public static DelayFrameTimer DelayFrameAction(int frame, Action onComplete, Action onUpdate = null, Object autoDestroyOwner = null); 18 | 19 | public static LoopTimer LoopAction(float interval, Action onComplete, Action onUpdate = null, bool useRealTime = false, bool executeOnStart = false, Object autoDestroyOwner = null); 20 | 21 | public static LoopUntilTimer LoopUntilAction(float interval, Func loopUntil, Action onComplete, Action onUpdate = null, Action onFinished = null, bool useRealTime = false, bool executeOnStart = false, Object autoDestroyOwner = null); 22 | 23 | public static LoopCountTimer LoopCountAction(float interval, int loopCount, Action onComplete, Action onUpdate = null, Action onFinished = null, bool useRealTime = false, bool executeOnStart = false, Object autoDestroyOwner = null); 24 | 25 | public static DelayTimer PersistenceDelayAction(float duration, Action onComplete, Action onUpdate = null, bool useRealTime = false, Object autoDestroyOwner = null); 26 | 27 | public static DelayFrameTimer PersistenceDelayFrameAction(int frame, Action onComplete, Action onUpdate = null, Object autoDestroyOwner = null); 28 | 29 | public static LoopTimer PersistenceLoopAction(float interval, Action onComplete, Action onUpdate = null, bool useRealTime = false, bool executeOnStart = false, Object autoDestroyOwner = null); 30 | 31 | public static LoopUntilTimer PersistenceLoopUntilAction(float interval, Func loopUntil, Action onComplete, Action onUpdate = null, Action onFinished = null, bool useRealTime = false, bool executeOnStart = false, Object autoDestroyOwner = null); 32 | 33 | public static LoopCountTimer PersistenceLoopCountAction(float interval, int loopCount, Action onComplete, Action onUpdate = null, Action onFinished = null, bool useRealTime = false, bool executeOnStart = false, Object autoDestroyOwner = null); 34 | ``` 35 | ## Motivation 36 | 37 | Out of the box, without this library, there are two main ways of handling timers in Unity: 38 | 39 | 1. Use a coroutine with the WaitForSeconds method. 40 | 2. Store the time that your timer started in a private variable (e.g. `startTime = Time.time`), then check in an Update call if `Time.time - startTime >= timerDuration`. 41 | 42 | The first method is verbose, forcing you to refactor your code to use IEnumerator functions. Furthermore, it necessitates having access to a MonoBehaviour instance to start the coroutine, meaning that solution will not work in non-MonoBehaviour classes. Finally, there is no way to prevent WaitForSeconds from being affected by changes to the [time scale](http://docs.unity3d.com/ScriptReference/Time-timeScale.html). 43 | 44 | The second method is error-prone, and hides away the actual game logic that you are trying to express. 45 | 46 | This library alleviates both of these concerns, making it easy to add an easy-to-read, expressive timer to any class in your Unity project. 47 | 48 | ## Features 49 | 50 | * Make a timer repeat by call Timer.LoopAction. 51 | ```c# 52 | private void Start() 53 | { 54 | Timer.LoopAction(5, loopTime => { Debug.LogError("Timer Called: " + loopTime); }); 55 | } 56 | ``` 57 | 58 | * Make a loop timer execute when start by setting `executeOnStart` to true. 59 | ```c# 60 | private void Start() 61 | { 62 | Timer.LoopAction(5, loopTime => { Debug.LogError("Timer Called: " + loopTime); }, executeOnStart: true); 63 | } 64 | ``` 65 | 66 | * Make a timer based on frame count by call Timer.DelayFrameAction. 67 | ```c# 68 | private void Start() 69 | { 70 | Timer.DelayFrameAction(5, () => { Debug.LogError("Timer Called"); }); 71 | } 72 | ``` 73 | 74 | * Measure time by [realtimeSinceStartup](http://docs.unity3d.com/ScriptReference/Time-realtimeSinceStartup.html) 75 | instead of scaled game time by setting [Obsolete("Use updateMode to instead.")]`useRealTime` to true. 76 | Default is false. 77 | ```c# 78 | private void Start() 79 | { 80 | Timer.DelayAction(5, () => { Debug.LogError("Timer Called"); }, useRealTime: true); 81 | } 82 | ``` 83 | 84 | * Measure time by [time](http://docs.unity3d.com/ScriptReference/Time-time.html) or [unscaledTime](http://docs.unity3d.com/ScriptReference/Time-unscaledTime.html) or [realtimeSinceStartup](http://docs.unity3d.com/ScriptReference/Time-realtimeSinceStartup.html) 85 | by setting `updateMode` to `Timer.UpdateMode.GameTime` or `Timer.UpdateMode.UnscaledGameTime` or `Timer.UpdateMode.RealTime`. 86 | Default is `Timer.UpdateMode.GameTime`. 87 | ```c# 88 | private void Start() 89 | { 90 | Timer.DelayAction(5, () => { Debug.LogError("Timer Called"); }, null, Timer.UpdateMode.UnscaledGameTime); 91 | } 92 | ``` 93 | 94 | * Cancel a timer after calling it. 95 | ```c# 96 | Timer timer; 97 | 98 | void Start() { 99 | timer = Timer.LoopAction(5, _ => { Debug.LogError("Timer Called"); }); 100 | } 101 | 102 | void Update() { 103 | if (Input.GetKeyDown(KeyCode.X)) { 104 | Timer.Cancel(timer); 105 | } 106 | } 107 | ``` 108 | 109 | * Attach the timer to a UnityEngine.Object by setting `autoDestroyOwner` to the UnityEngine.Object, so that the timer is destroyed when the UnityEngine.Object is. 110 | 111 | Very often, a timer called from a Component will manipulate that component's state. Thus, it is common practice to cancel the timer in the OnDestroy method of the Component. We've added a convenient extension method that attaches a Timer to a Component such that it will automatically cancel the timer when the Component is detected as null. 112 | ```c# 113 | public class CoolMonoBehaviour : MonoBehaviour { 114 | 115 | private void Start() 116 | { 117 | //The timer will cancel when the Component is destroyed; 118 | Timer.DelayAction(5, () => { Debug.LogError("Timer Called"); }, useRealTime: true, autoDestroyOwner: this); 119 | } 120 | 121 | private void Update() 122 | { 123 | // This code could destroy the object at any time! 124 | if (Input.GetKeyDown(KeyCode.X)) { 125 | GameObject.Destroy(this.gameObject); 126 | } 127 | } 128 | } 129 | ``` 130 | 131 | * Update a value gradually over time using the `onUpdate` callback. 132 | 133 | ```c# 134 | // Change a color from white to red over the course of five seconds. 135 | Color color = Color.white; 136 | float transitionDuration = 5f; 137 | 138 | Timer.DelayAction(transitionDuration, 139 | onUpdate: secondsElapsed => color.r = 255 * (secondsElapsed / transitionDuration), 140 | onComplete: () => Debug.Log("Color is now red")); 141 | ``` 142 | 143 | * A number of other useful features are included! 144 | 145 | - `timer.Pause()` 146 | - `timer.Resume()` 147 | - `timer.Cancel()` 148 | - `timer.Restart()` 149 | - `timer.GetTimeElapsed()` 150 | - `timer.GetTimeRemaining()` 151 | - `timer.GetRatioComplete()` 152 | - `timer.isDone` 153 | - `Timer.CancelAllRegisteredTimers()` 154 | - `Timer.CancelAllRegisteredTimersByOwner(owner)` 155 | - `Timer.PauseAllRegisteredTimers()` 156 | - `Timer.ResumeAllRegisteredTimers()` 157 | 158 | * Make a timer not effect by `Timer.XXXAllRegisteredTimers()` function by call `Timer.PersistenceXXX()` function. 159 | ```c# 160 | Timer timer; 161 | 162 | void Start() { 163 | //The timer will not cancel when Timer.XXXAllRegisteredTimers(); 164 | timer = Timer.PersistenceLoopAction(5, _ => { Debug.LogError("Timer Called"); }); 165 | } 166 | 167 | void Update() { 168 | //No effect to timer 169 | if (Input.GetKeyDown(KeyCode.X)) 170 | Timer.CancelAllRegisteredTimers(); 171 | 172 | //Only this can cancel persistence timer 173 | if(Input.GetKeyDown(KeyCode.C)) 174 | Timer.Cancel(timer);//same to timer?.Cancel(); 175 | } 176 | ``` 177 | 178 | * All timer generator functions can shortcut call by using Component/GameObject Extensions functions, and the timer will attach to the Component/GameObject so that the timer is destroyed when the Component/GameObject is. 179 | ```c# 180 | void Start() { 181 | //The timer will attach to the Component instance. 182 | this.DelayAction(5, () => { Debug.LogError("Timer Called"); }); 183 | } 184 | ``` 185 | 186 | 187 | * A test scene + script demoing all the features is included with the package in the `/Example` folder. 188 | 189 | ## Usage Notes / Caveats 190 | * All timers will not destroy when change scene, because TimerManager is `DontDestroyOnLoad`. 191 | -------------------------------------------------------------------------------- /Source.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: a5f4fde1bc57344568b469fed5cb7483 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Source/DelayFrameTimer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using UnityEngine; 3 | 4 | namespace GameUtil 5 | { 6 | public class DelayFrameTimer : Timer 7 | { 8 | protected Action _onComplete; 9 | 10 | protected override float GetWorldTime() 11 | { 12 | return Time.frameCount; 13 | } 14 | 15 | public DelayFrameTimer(bool isPersistence, int frame, Action onComplete, Action onUpdate, 16 | UnityEngine.Object autoDestroyOwner) 17 | : base(isPersistence, frame, onUpdate, UpdateMode.GameTime, autoDestroyOwner) 18 | { 19 | _onComplete = onComplete; 20 | } 21 | 22 | protected override void Update() 23 | { 24 | if (!CheckUpdate()) return; 25 | 26 | SafeCall(_onUpdate, GetTimeElapsed()); 27 | //minus 1e-4 to avoid float precision cause equal judge fail 28 | if (GetWorldTime() >= GetFireTime() - 1e-4) 29 | { 30 | isCompleted = true; 31 | SafeCall(_onComplete); 32 | } 33 | } 34 | 35 | public void Restart(int newFrame) 36 | { 37 | duration = newFrame; 38 | Restart(); 39 | } 40 | 41 | public void Restart(int newFrame, Action newOnComplete, Action newOnUpdate) 42 | { 43 | duration = newFrame; 44 | _onComplete = newOnComplete; 45 | _onUpdate = newOnUpdate; 46 | Restart(); 47 | } 48 | } 49 | } -------------------------------------------------------------------------------- /Source/DelayFrameTimer.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 86fe651ed8f94630bb2d00de1b557f0e 3 | timeCreated: 1583734285 -------------------------------------------------------------------------------- /Source/DelayTimer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace GameUtil 4 | { 5 | public class DelayTimer : Timer 6 | { 7 | protected Action _onComplete; 8 | 9 | public DelayTimer(bool isPersistence, float duration, Action onComplete, Action onUpdate, 10 | bool usesRealTime, UnityEngine.Object autoDestroyOwner) 11 | : base(isPersistence, duration, onUpdate, usesRealTime, autoDestroyOwner) 12 | { 13 | _onComplete = onComplete; 14 | } 15 | 16 | public DelayTimer(bool isPersistence, float duration, Action onComplete, Action onUpdate, 17 | UpdateMode updateMode, UnityEngine.Object autoDestroyOwner) 18 | : base(isPersistence, duration, onUpdate, updateMode, autoDestroyOwner) 19 | { 20 | _onComplete = onComplete; 21 | } 22 | 23 | protected override void Update() 24 | { 25 | if (!CheckUpdate()) return; 26 | 27 | if (_onUpdate != null) 28 | SafeCall(_onUpdate, GetTimeElapsed()); 29 | 30 | if (GetWorldTime() >= GetFireTime()) 31 | { 32 | isCompleted = true; 33 | SafeCall(_onComplete); 34 | } 35 | } 36 | 37 | public void Restart(float newDuration) 38 | { 39 | duration = newDuration; 40 | Restart(); 41 | } 42 | 43 | public void Restart(float newDuration, bool newUseRealTime) 44 | { 45 | duration = newDuration; 46 | Restart(newUseRealTime); 47 | } 48 | 49 | public void Restart(float newDuration, UpdateMode newUpdateMode) 50 | { 51 | duration = newDuration; 52 | Restart(newUpdateMode); 53 | } 54 | 55 | public void Restart(float newDuration, Action newOnComplete, Action newOnUpdate, bool newUseRealTime) 56 | { 57 | duration = newDuration; 58 | _onComplete = newOnComplete; 59 | _onUpdate = newOnUpdate; 60 | Restart(newUseRealTime); 61 | } 62 | 63 | public void Restart(float newDuration, Action newOnComplete, Action newOnUpdate, UpdateMode newUpdateMode) 64 | { 65 | duration = newDuration; 66 | _onComplete = newOnComplete; 67 | _onUpdate = newOnUpdate; 68 | Restart(newUpdateMode); 69 | } 70 | } 71 | } -------------------------------------------------------------------------------- /Source/DelayTimer.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 0e4d1d8673094eef836cf944441c7e0d 3 | timeCreated: 1583734352 -------------------------------------------------------------------------------- /Source/LoopCountTimer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace GameUtil 4 | { 5 | public class LoopCountTimer : LoopUntilTimer 6 | { 7 | public int loopCount { protected set; get; } 8 | 9 | public LoopCountTimer(bool isPersistence, float interval, int loopCount, Action onComplete, 10 | Action onUpdate, Action onFinished, bool usesRealTime, bool executeOnStart, UnityEngine.Object autoDestroyOwner) 11 | : base(isPersistence, interval, null, onComplete, onUpdate, onFinished, usesRealTime, executeOnStart, autoDestroyOwner) 12 | { 13 | this.loopCount = loopCount; 14 | _loopUntilFunc = LoopCountUntil; 15 | } 16 | 17 | public LoopCountTimer(bool isPersistence, float interval, int loopCount, Action onComplete, 18 | Action onUpdate, Action onFinished, UpdateMode updateMode, bool executeOnStart, UnityEngine.Object autoDestroyOwner) 19 | : base(isPersistence, interval, null, onComplete, onUpdate, onFinished, updateMode, executeOnStart, autoDestroyOwner) 20 | { 21 | this.loopCount = loopCount; 22 | _loopUntilFunc = LoopCountUntil; 23 | } 24 | 25 | private bool LoopCountUntil(LoopUntilTimer timer) 26 | { 27 | return loopTimes >= loopCount; 28 | } 29 | 30 | public void Restart(float newInterval, int newLoopCount) 31 | { 32 | loopCount = newLoopCount; 33 | base.Restart(newInterval); 34 | } 35 | 36 | //Avoid _loopUntilFunc reassignment 37 | public sealed override void Restart(float newInterval, Func newLoopUntil) 38 | { 39 | base.Restart(newInterval, LoopCountUntil); 40 | } 41 | 42 | //Avoid _loopUntilFunc reassignment 43 | public sealed override void Restart(float newInterval, Func newLoopUntil, Action newOnComplete, Action newOnUpdate, Action newOnFinished, bool newUsesRealTime, bool newExecuteOnStart) 44 | { 45 | base.Restart(newInterval, LoopCountUntil, newOnComplete, newOnUpdate, newOnFinished, newUsesRealTime, newExecuteOnStart); 46 | } 47 | 48 | //Avoid _loopUntilFunc reassignment 49 | public sealed override void Restart(float newInterval, Func newLoopUntil, Action newOnComplete, Action newOnUpdate, Action newOnFinished, UpdateMode newUpdateMode, bool newExecuteOnStart) 50 | { 51 | base.Restart(newInterval, LoopCountUntil, newOnComplete, newOnUpdate, newOnFinished, newUpdateMode, newExecuteOnStart); 52 | } 53 | 54 | public void Restart(float newInterval, int newLoopCount, Action newOnComplete, Action newOnUpdate, Action newOnFinished, bool newUsesRealTime, bool newExecuteOnStart) 55 | { 56 | loopCount = newLoopCount; 57 | Restart(newInterval, LoopCountUntil, newOnComplete, newOnUpdate, newOnFinished, newUsesRealTime, newExecuteOnStart); 58 | } 59 | 60 | public void Restart(float newInterval, int newLoopCount, Action newOnComplete, Action newOnUpdate, Action newOnFinished, UpdateMode newUpdateMode, bool newExecuteOnStart) 61 | { 62 | loopCount = newLoopCount; 63 | Restart(newInterval, LoopCountUntil, newOnComplete, newOnUpdate, newOnFinished, newUpdateMode, newExecuteOnStart); 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /Source/LoopCountTimer.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 2f6fff597ecb42828840c4bb2ab4aecb 3 | timeCreated: 1627269802 -------------------------------------------------------------------------------- /Source/LoopTimer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace GameUtil 4 | { 5 | public class LoopTimer : Timer 6 | { 7 | /// 8 | /// Parameter is loopTime. 9 | /// 10 | protected Action _onComplete; 11 | public bool executeOnStart { protected set; get; } 12 | 13 | [Obsolete("Use loopTimes instead.")] 14 | public int loopTime => loopTimes; 15 | /// 16 | /// How many times does the LoopTimer looped. 17 | /// 18 | public int loopTimes { private set; get; } 19 | 20 | protected virtual void OnComplete() 21 | { 22 | } 23 | 24 | public LoopTimer(bool isPersistence, float interval, Action onComplete, 25 | Action onUpdate, bool usesRealTime, bool executeOnStart, UnityEngine.Object autoDestroyOwner) 26 | : base(isPersistence, interval, onUpdate, usesRealTime, autoDestroyOwner) 27 | { 28 | _onComplete = onComplete; 29 | this.executeOnStart = executeOnStart; 30 | } 31 | 32 | public LoopTimer(bool isPersistence, float interval, Action onComplete, 33 | Action onUpdate, UpdateMode updateMode, bool executeOnStart, UnityEngine.Object autoDestroyOwner) 34 | : base(isPersistence, interval, onUpdate, updateMode, autoDestroyOwner) 35 | { 36 | _onComplete = onComplete; 37 | this.executeOnStart = executeOnStart; 38 | } 39 | 40 | protected override void OnInit() 41 | { 42 | //avoid virtual member call in constructor 43 | if (executeOnStart) 44 | Complete(); 45 | } 46 | 47 | protected override void OnRestart() 48 | { 49 | loopTimes = 0; 50 | if (executeOnStart) 51 | Complete(); 52 | } 53 | 54 | protected override void Update() 55 | { 56 | if (!CheckUpdate()) return; 57 | 58 | if (_onUpdate != null) 59 | SafeCall(_onUpdate, GetTimeElapsed()); 60 | 61 | var timeDifference = GetWorldTime() - GetFireTime(); 62 | //Loop call until cannot fire 63 | while (timeDifference >= 0) 64 | { 65 | Complete(); 66 | if (isDone) 67 | break; 68 | _startTime = GetWorldTime() - timeDifference; //Avoid time error accumulation 69 | timeDifference = GetWorldTime() - GetFireTime(); 70 | } 71 | } 72 | 73 | private void Complete() 74 | { 75 | loopTimes++; 76 | SafeCall(_onComplete, loopTimes); 77 | OnComplete(); 78 | } 79 | 80 | public void Restart(float newInterval) 81 | { 82 | duration = newInterval; 83 | Restart(); 84 | } 85 | 86 | public void Restart(float newInterval, Action newOnComplete, Action newOnUpdate, bool newUsesRealTime, bool newExecuteOnStart) 87 | { 88 | duration = newInterval; 89 | _onComplete = newOnComplete; 90 | _onUpdate = newOnUpdate; 91 | executeOnStart = newExecuteOnStart; 92 | Restart(newUsesRealTime); 93 | } 94 | 95 | public void Restart(float newInterval, Action newOnComplete, Action newOnUpdate, UpdateMode newUpdateMode, bool newExecuteOnStart) 96 | { 97 | duration = newInterval; 98 | _onComplete = newOnComplete; 99 | _onUpdate = newOnUpdate; 100 | executeOnStart = newExecuteOnStart; 101 | Restart(newUpdateMode); 102 | } 103 | } 104 | } -------------------------------------------------------------------------------- /Source/LoopTimer.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: c9351d2d8abd48eea9d1a266f5eb831c 3 | timeCreated: 1583734327 -------------------------------------------------------------------------------- /Source/LoopUntilTimer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace GameUtil 4 | { 5 | public class LoopUntilTimer : LoopTimer 6 | { 7 | protected Func _loopUntilFunc; 8 | private Action _onFinished; 9 | 10 | public LoopUntilTimer(bool isPersistence, float interval, Func loopUntil, Action onComplete, 11 | Action onUpdate, Action onFinished, bool usesRealTime, bool executeOnStart, UnityEngine.Object autoDestroyOwner) 12 | : base(isPersistence, interval, onComplete, onUpdate, usesRealTime, executeOnStart, autoDestroyOwner) 13 | { 14 | _loopUntilFunc = loopUntil; 15 | _onFinished = onFinished; 16 | } 17 | 18 | public LoopUntilTimer(bool isPersistence, float interval, Func loopUntil, Action onComplete, 19 | Action onUpdate, Action onFinished, UpdateMode updateMode, bool executeOnStart, UnityEngine.Object autoDestroyOwner) 20 | : base(isPersistence, interval, onComplete, onUpdate, updateMode, executeOnStart, autoDestroyOwner) 21 | { 22 | _loopUntilFunc = loopUntil; 23 | _onFinished = onFinished; 24 | } 25 | 26 | protected override void OnComplete() 27 | { 28 | if (_loopUntilFunc == null || !SafeCall(_loopUntilFunc, this)) return; 29 | //LoopTimer completed! 30 | isCompleted = true; 31 | SafeCall(_onFinished); 32 | } 33 | 34 | public virtual void Restart(float newInterval, Func newLoopUntil) 35 | { 36 | _loopUntilFunc = newLoopUntil; 37 | Restart(newInterval); 38 | } 39 | 40 | public virtual void Restart(float newInterval, Func newLoopUntil, Action newOnComplete, Action newOnUpdate, Action newOnFinished, bool newUsesRealTime, bool newExecuteOnStart) 41 | { 42 | _loopUntilFunc = newLoopUntil; 43 | _onFinished = newOnFinished; 44 | Restart(newInterval, newOnComplete, newOnUpdate, newUsesRealTime, newExecuteOnStart); 45 | } 46 | 47 | public virtual void Restart(float newInterval, Func newLoopUntil, Action newOnComplete, Action newOnUpdate, Action newOnFinished, UpdateMode newUpdateMode, bool newExecuteOnStart) 48 | { 49 | _loopUntilFunc = newLoopUntil; 50 | _onFinished = newOnFinished; 51 | Restart(newInterval, newOnComplete, newOnUpdate, newUpdateMode, newExecuteOnStart); 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /Source/LoopUntilTimer.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: b571b631781941df980a809fd649c9b7 3 | timeCreated: 1627268722 -------------------------------------------------------------------------------- /Source/Timer.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using System; 3 | using System.Collections.Generic; 4 | using Object = UnityEngine.Object; 5 | 6 | namespace GameUtil 7 | { 8 | /// 9 | /// Allows you to run events on a delay without the use of s 10 | /// or s. 11 | /// 12 | public abstract class Timer 13 | { 14 | public enum UpdateMode 15 | { 16 | /// 17 | /// Update is based on Time.time. Time.timeScale does affect. 18 | /// 19 | GameTime, 20 | /// 21 | /// Update is based on Time.unscaledTime. Time.timeScale does not affect, but Application pause does affect. 22 | /// 23 | UnscaledGameTime, 24 | /// 25 | /// Update is based on Time.realtimeSinceStartup. Time.timeScale and Application pause do not affect. 26 | /// 27 | RealTime, 28 | } 29 | 30 | #region Public Properties/Fields 31 | 32 | /// 33 | /// How long the timer takes to complete from start to finish. (seconds/frame) 34 | /// 35 | public float duration { get; protected set; } 36 | 37 | /// 38 | /// whether the timer is persistence 39 | /// 40 | public bool isPersistence { get; } 41 | 42 | /// 43 | /// Whether or not the timer completed running. This is false if the timer was cancelled. 44 | /// 45 | public bool isCompleted { get; protected set; } 46 | 47 | /// 48 | /// Whether the timer uses real-time or game-time or unscaled-game-time. Real time is unaffected by changes to the timescale 49 | /// of the game(e.g. pausing, slow-mo), while game time is affected. 50 | /// 51 | public UpdateMode updateMode { get; protected set; } 52 | 53 | /// 54 | /// Whether the timer uses real-time or game-time. Real time is unaffected by changes to the timescale 55 | /// of the game(e.g. pausing, slow-mo), while game time is affected. 56 | /// 57 | [Obsolete("Use updateMode to instead.")] 58 | public bool usesRealTime => updateMode != UpdateMode.GameTime; 59 | 60 | /// 61 | /// Whether the timer is currently paused. 62 | /// 63 | public bool isPaused 64 | { 65 | get { return this._timeElapsedBeforePause.HasValue; } 66 | } 67 | 68 | /// 69 | /// Whether or not the timer was cancelled. 70 | /// 71 | public bool isCancelled 72 | { 73 | get { return this._timeElapsedBeforeCancel.HasValue; } 74 | } 75 | 76 | /// 77 | /// Get whether or not the timer has finished running for any reason. 78 | /// 79 | public bool isDone 80 | { 81 | get { return this.isCompleted || this.isCancelled || this.isOwnerDestroyed; } 82 | } 83 | 84 | // after the auto destroy owner is destroyed, the timer will expire 85 | // this way you don't run into any annoying bugs with timers running and accessing objects 86 | // after they have been destroyed 87 | public Object autoDestroyOwner { get; } 88 | public bool hasAutoDestroyOwner { get; } 89 | private bool isOwnerDestroyed 90 | { 91 | get 92 | { 93 | if (!hasAutoDestroyOwner || autoDestroyOwner) return false; 94 | if (!_timeElapsedBeforeAutoDestroy.HasValue) 95 | _timeElapsedBeforeAutoDestroy = GetTimeElapsed(); 96 | return true; 97 | } 98 | } 99 | 100 | #endregion 101 | 102 | #region Public Static Methods 103 | 104 | public static DelayTimer DelayAction(float duration, Action onComplete, Action onUpdate = null, 105 | bool useRealTime = false, Object autoDestroyOwner = null) 106 | { 107 | return DelayActionInternal(false, duration, onComplete, onUpdate, useRealTime, autoDestroyOwner); 108 | } 109 | 110 | public static DelayTimer DelayAction(float duration, Action onComplete, Action onUpdate, 111 | UpdateMode updateMode, Object autoDestroyOwner = null) 112 | { 113 | return DelayActionInternal(false, duration, onComplete, onUpdate, updateMode, autoDestroyOwner); 114 | } 115 | 116 | public static DelayFrameTimer DelayFrameAction(int frame, Action onComplete, Action onUpdate = null, 117 | Object autoDestroyOwner = null) 118 | { 119 | return DelayFrameActionInternal(false, frame, onComplete, onUpdate, autoDestroyOwner); 120 | } 121 | 122 | public static LoopTimer LoopAction(float interval, Action onComplete, Action onUpdate = null, 123 | bool useRealTime = false, bool executeOnStart = false, Object autoDestroyOwner = null) 124 | { 125 | return LoopActionInternal(false, interval, onComplete, onUpdate, useRealTime, executeOnStart, 126 | autoDestroyOwner); 127 | } 128 | 129 | public static LoopTimer LoopAction(float interval, Action onComplete, Action onUpdate, 130 | UpdateMode updateMode, bool executeOnStart = false, Object autoDestroyOwner = null) 131 | { 132 | return LoopActionInternal(false, interval, onComplete, onUpdate, updateMode, executeOnStart, 133 | autoDestroyOwner); 134 | } 135 | 136 | public static LoopUntilTimer LoopUntilAction(float interval, Func loopUntil, Action onComplete, 137 | Action onUpdate = null, Action onFinished = null, 138 | bool useRealTime = false, bool executeOnStart = false, Object autoDestroyOwner = null) 139 | { 140 | return LoopUntilActionInternal(false, interval, loopUntil, onComplete, onUpdate, onFinished, useRealTime, 141 | executeOnStart, autoDestroyOwner); 142 | } 143 | 144 | public static LoopUntilTimer LoopUntilAction(float interval, Func loopUntil, Action onComplete, 145 | Action onUpdate, Action onFinished, 146 | UpdateMode updateMode, bool executeOnStart = false, Object autoDestroyOwner = null) 147 | { 148 | return LoopUntilActionInternal(false, interval, loopUntil, onComplete, onUpdate, onFinished, updateMode, 149 | executeOnStart, autoDestroyOwner); 150 | } 151 | 152 | public static LoopCountTimer LoopCountAction(float interval, int loopCount, Action onComplete, 153 | Action onUpdate = null, Action onFinished = null, 154 | bool useRealTime = false, bool executeOnStart = false, Object autoDestroyOwner = null) 155 | { 156 | return LoopCountActionInternal(false, interval, loopCount, onComplete, onUpdate, onFinished, useRealTime, 157 | executeOnStart, autoDestroyOwner); 158 | } 159 | 160 | public static LoopCountTimer LoopCountAction(float interval, int loopCount, Action onComplete, 161 | Action onUpdate, Action onFinished, 162 | UpdateMode updateMode, bool executeOnStart = false, Object autoDestroyOwner = null) 163 | { 164 | return LoopCountActionInternal(false, interval, loopCount, onComplete, onUpdate, onFinished, updateMode, 165 | executeOnStart, autoDestroyOwner); 166 | } 167 | 168 | //Persistence 169 | public static DelayTimer PersistenceDelayAction(float duration, Action onComplete, 170 | Action onUpdate = null, bool useRealTime = false, Object autoDestroyOwner = null) 171 | { 172 | return DelayActionInternal(true, duration, onComplete, onUpdate, useRealTime, autoDestroyOwner); 173 | } 174 | 175 | public static DelayTimer PersistenceDelayAction(float duration, Action onComplete, 176 | Action onUpdate, UpdateMode updateMode, Object autoDestroyOwner = null) 177 | { 178 | return DelayActionInternal(true, duration, onComplete, onUpdate, updateMode, autoDestroyOwner); 179 | } 180 | 181 | public static DelayFrameTimer PersistenceDelayFrameAction(int frame, Action onComplete, 182 | Action onUpdate = null, Object autoDestroyOwner = null) 183 | { 184 | return DelayFrameActionInternal(true, frame, onComplete, onUpdate, autoDestroyOwner); 185 | } 186 | 187 | public static LoopTimer PersistenceLoopAction(float interval, Action onComplete, Action onUpdate = null, 188 | bool useRealTime = false, bool executeOnStart = false, Object autoDestroyOwner = null) 189 | { 190 | return LoopActionInternal(true, interval, onComplete, onUpdate, useRealTime, executeOnStart, 191 | autoDestroyOwner); 192 | } 193 | 194 | public static LoopTimer PersistenceLoopAction(float interval, Action onComplete, Action onUpdate, 195 | UpdateMode updateMode, bool executeOnStart = false, Object autoDestroyOwner = null) 196 | { 197 | return LoopActionInternal(true, interval, onComplete, onUpdate, updateMode, executeOnStart, 198 | autoDestroyOwner); 199 | } 200 | 201 | public static LoopUntilTimer PersistenceLoopUntilAction(float interval, Func loopUntil, Action onComplete, 202 | Action onUpdate = null, Action onFinished = null, 203 | bool useRealTime = false, bool executeOnStart = false, Object autoDestroyOwner = null) 204 | { 205 | return LoopUntilActionInternal(true, interval, loopUntil, onComplete, onUpdate, onFinished, useRealTime, 206 | executeOnStart, autoDestroyOwner); 207 | } 208 | 209 | public static LoopUntilTimer PersistenceLoopUntilAction(float interval, Func loopUntil, Action onComplete, 210 | Action onUpdate, Action onFinished, 211 | UpdateMode updateMode, bool executeOnStart = false, Object autoDestroyOwner = null) 212 | { 213 | return LoopUntilActionInternal(true, interval, loopUntil, onComplete, onUpdate, onFinished, updateMode, 214 | executeOnStart, autoDestroyOwner); 215 | } 216 | 217 | public static LoopCountTimer PersistenceLoopCountAction(float interval, int loopCount, Action onComplete, 218 | Action onUpdate = null, Action onFinished = null, 219 | bool useRealTime = false, bool executeOnStart = false, Object autoDestroyOwner = null) 220 | { 221 | return LoopCountActionInternal(true, interval, loopCount, onComplete, onUpdate, onFinished, useRealTime, 222 | executeOnStart, autoDestroyOwner); 223 | } 224 | 225 | public static LoopCountTimer PersistenceLoopCountAction(float interval, int loopCount, Action onComplete, 226 | Action onUpdate, Action onFinished, 227 | UpdateMode updateMode, bool executeOnStart = false, Object autoDestroyOwner = null) 228 | { 229 | return LoopCountActionInternal(true, interval, loopCount, onComplete, onUpdate, onFinished, updateMode, 230 | executeOnStart, autoDestroyOwner); 231 | } 232 | 233 | /// 234 | /// Restart a timer. The main benefit of this over the method on the instance is that you will not get 235 | /// a if the timer is null. 236 | /// 237 | /// The timer to restart. 238 | public static void Restart(Timer timer) 239 | { 240 | if (timer != null) 241 | { 242 | timer.Restart(); 243 | } 244 | } 245 | 246 | /// 247 | /// Cancels a timer. The main benefit of this over the method on the instance is that you will not get 248 | /// a if the timer is null. 249 | /// 250 | /// The timer to cancel. 251 | public static void Cancel(Timer timer) 252 | { 253 | if (timer != null) 254 | { 255 | timer.Cancel(); 256 | } 257 | } 258 | 259 | /// 260 | /// Pause a timer. The main benefit of this over the method on the instance is that you will not get 261 | /// a if the timer is null. 262 | /// 263 | /// The timer to pause. 264 | public static void Pause(Timer timer) 265 | { 266 | if (timer != null) 267 | { 268 | timer.Pause(); 269 | } 270 | } 271 | 272 | /// 273 | /// Resume a timer. The main benefit of this over the method on the instance is that you will not get 274 | /// a if the timer is null. 275 | /// 276 | /// The timer to resume. 277 | public static void Resume(Timer timer) 278 | { 279 | if (timer != null) 280 | { 281 | timer.Resume(); 282 | } 283 | } 284 | 285 | public static void CancelAllRegisteredTimersByOwner(Object owner) 286 | { 287 | if (_manager != null) 288 | { 289 | _manager.CancelAllTimersByOwner(owner); 290 | } 291 | 292 | // if the manager doesn't exist, we don't have any registered timers yet, so don't 293 | // need to do anything in this case 294 | } 295 | 296 | public static void CancelAllRegisteredTimers() 297 | { 298 | if (_manager != null) 299 | { 300 | _manager.CancelAllTimers(); 301 | } 302 | 303 | // if the manager doesn't exist, we don't have any registered timers yet, so don't 304 | // need to do anything in this case 305 | } 306 | 307 | public static void PauseAllRegisteredTimers() 308 | { 309 | if (_manager != null) 310 | { 311 | _manager.PauseAllTimers(); 312 | } 313 | 314 | // if the manager doesn't exist, we don't have any registered timers yet, so don't 315 | // need to do anything in this case 316 | } 317 | 318 | public static void ResumeAllRegisteredTimers() 319 | { 320 | if (_manager != null) 321 | { 322 | _manager.ResumeAllTimers(); 323 | } 324 | 325 | // if the manager doesn't exist, we don't have any registered timers yet, so don't 326 | // need to do anything in this case 327 | } 328 | 329 | #endregion 330 | 331 | #region Public Methods 332 | 333 | /// 334 | /// Restart a timer that is in-progress or done. The timer's on completion callback will not be called. 335 | /// 336 | public void Restart() 337 | { 338 | //auto destroy. return 339 | if (isOwnerDestroyed) return; 340 | 341 | isCompleted = false; 342 | _startTime = GetWorldTime(); 343 | _lastUpdateTime = _startTime; 344 | _timeElapsedBeforeCancel = null; 345 | _timeElapsedBeforePause = null; 346 | _timeElapsedBeforeAutoDestroy = null; 347 | OnRestart(); 348 | Register(); 349 | } 350 | 351 | public void Restart(bool newUseRealTime) 352 | { 353 | Restart(GetUpdateMode(newUseRealTime)); 354 | } 355 | 356 | public void Restart(UpdateMode newUpdateMode) 357 | { 358 | updateMode = newUpdateMode; 359 | Restart(); 360 | } 361 | 362 | /// 363 | /// Stop a timer that is in-progress or paused. The timer's on completion callback will not be called. 364 | /// 365 | public void Cancel() 366 | { 367 | if (this.isDone) 368 | { 369 | return; 370 | } 371 | 372 | this._timeElapsedBeforeCancel = this.GetTimeElapsed(); 373 | this._timeElapsedBeforePause = null; 374 | } 375 | 376 | /// 377 | /// Pause a running timer. A paused timer can be resumed from the same point it was paused. 378 | /// 379 | public void Pause() 380 | { 381 | if (this.isPaused || this.isDone) 382 | { 383 | return; 384 | } 385 | 386 | this._timeElapsedBeforePause = this.GetTimeElapsed(); 387 | } 388 | 389 | /// 390 | /// Continue a paused timer. Does nothing if the timer has not been paused. 391 | /// 392 | public void Resume() 393 | { 394 | if (!this.isPaused || this.isDone) 395 | { 396 | return; 397 | } 398 | 399 | this._timeElapsedBeforePause = null; 400 | } 401 | 402 | /// 403 | /// Get how many seconds/frame have elapsed since the start of this timer's current cycle. 404 | /// 405 | /// The number of seconds that have elapsed since the start of this timer's current cycle, i.e. 406 | /// the current loop if the timer is looped, or the start if it isn't. 407 | /// 408 | /// If the timer has finished running, this is equal to the duration. 409 | /// 410 | /// If the timer was cancelled/paused, this is equal to the number of seconds that passed between the timer 411 | /// starting and when it was cancelled/paused. 412 | public float GetTimeElapsed() 413 | { 414 | if (this.isCompleted) 415 | { 416 | return this.duration; 417 | } 418 | 419 | return this._timeElapsedBeforeCancel ?? 420 | this._timeElapsedBeforePause ?? 421 | this._timeElapsedBeforeAutoDestroy ?? 422 | this.GetWorldTime() - this._startTime; 423 | } 424 | 425 | /// 426 | /// Get how many seconds/frame remain before the timer completes. 427 | /// 428 | /// The number of seconds that remain to be elapsed until the timer is completed. A timer 429 | /// is only elapsing time if it is not paused, cancelled, or completed. This will be equal to zero 430 | /// if the timer completed. 431 | public float GetTimeRemaining() 432 | { 433 | return this.duration - this.GetTimeElapsed(); 434 | } 435 | 436 | /// 437 | /// Get how much progress the timer has made from start to finish as a ratio. 438 | /// 439 | /// A value from 0 to 1 indicating how much of the timer's duration has been elapsed. 440 | public float GetRatioComplete() 441 | { 442 | return this.GetTimeElapsed() / this.duration; 443 | } 444 | 445 | /// 446 | /// Get how much progress the timer has left to make as a ratio. 447 | /// 448 | /// A value from 0 to 1 indicating how much of the timer's duration remains to be elapsed. 449 | public float GetRatioRemaining() 450 | { 451 | return this.GetTimeRemaining() / this.duration; 452 | } 453 | 454 | #endregion 455 | 456 | #region Private Static Methods 457 | 458 | private static void InitTimerManager() 459 | { 460 | if (_manager != null) return; 461 | // create a manager object to update all the timers if one does not already exist. 462 | _manager = Object.FindObjectOfType(); 463 | if (_manager == null) 464 | _manager = new GameObject(nameof(TimerManager)).AddComponent(); 465 | Object.DontDestroyOnLoad(_manager.transform.root.gameObject); 466 | } 467 | 468 | private static UpdateMode GetUpdateMode(bool usesRealTime) 469 | { 470 | return usesRealTime ? UpdateMode.RealTime : UpdateMode.GameTime; 471 | } 472 | 473 | private static DelayTimer DelayActionInternal(bool isPersistence, float duration, Action onComplete, 474 | Action onUpdate, bool useRealTime, Object autoDestroyOwner) 475 | { 476 | //Check 477 | if (duration <= 0) 478 | { 479 | SafeCall(onUpdate, 0); 480 | SafeCall(onComplete); 481 | return null; 482 | } 483 | 484 | var timer = new DelayTimer(isPersistence, duration, onComplete, onUpdate, useRealTime, autoDestroyOwner); 485 | timer.Init(); 486 | return timer; 487 | } 488 | 489 | private static DelayTimer DelayActionInternal(bool isPersistence, float duration, Action onComplete, 490 | Action onUpdate, UpdateMode updateMode, Object autoDestroyOwner) 491 | { 492 | //Check 493 | if (duration <= 0) 494 | { 495 | SafeCall(onUpdate, 0); 496 | SafeCall(onComplete); 497 | return null; 498 | } 499 | 500 | var timer = new DelayTimer(isPersistence, duration, onComplete, onUpdate, updateMode, autoDestroyOwner); 501 | timer.Init(); 502 | return timer; 503 | } 504 | 505 | private static DelayFrameTimer DelayFrameActionInternal(bool isPersistence, int frame, Action onComplete, 506 | Action onUpdate, Object autoDestroyOwner) 507 | { 508 | //Check 509 | if (frame <= 0) 510 | { 511 | SafeCall(onUpdate, 0); 512 | SafeCall(onComplete); 513 | return null; 514 | } 515 | 516 | var timer = new DelayFrameTimer(isPersistence, frame, onComplete, onUpdate, autoDestroyOwner); 517 | timer.Init(); 518 | return timer; 519 | } 520 | 521 | private static LoopTimer LoopActionInternal(bool isPersistence, float interval, Action onComplete, Action onUpdate, 522 | bool useRealTime, bool executeOnStart, Object autoDestroyOwner) 523 | { 524 | var timer = new LoopTimer(isPersistence, interval, onComplete, onUpdate, useRealTime, executeOnStart, autoDestroyOwner); 525 | timer.Init(); 526 | return timer; 527 | } 528 | 529 | private static LoopTimer LoopActionInternal(bool isPersistence, float interval, Action onComplete, Action onUpdate, 530 | UpdateMode updateMode, bool executeOnStart, Object autoDestroyOwner) 531 | { 532 | var timer = new LoopTimer(isPersistence, interval, onComplete, onUpdate, updateMode, executeOnStart, autoDestroyOwner); 533 | timer.Init(); 534 | return timer; 535 | } 536 | 537 | private static LoopUntilTimer LoopUntilActionInternal(bool isPersistence, float interval, Func loopUntil, 538 | Action onComplete, Action onUpdate, Action onFinished, 539 | bool useRealTime, bool executeOnStart, Object autoDestroyOwner) 540 | { 541 | var timer = new LoopUntilTimer(isPersistence, interval, loopUntil, onComplete, onUpdate, 542 | onFinished, useRealTime, executeOnStart, autoDestroyOwner); 543 | timer.Init(); 544 | return timer; 545 | } 546 | 547 | private static LoopUntilTimer LoopUntilActionInternal(bool isPersistence, float interval, Func loopUntil, 548 | Action onComplete, Action onUpdate, Action onFinished, 549 | UpdateMode updateMode, bool executeOnStart, Object autoDestroyOwner) 550 | { 551 | var timer = new LoopUntilTimer(isPersistence, interval, loopUntil, onComplete, onUpdate, 552 | onFinished, updateMode, executeOnStart, autoDestroyOwner); 553 | timer.Init(); 554 | return timer; 555 | } 556 | 557 | private static LoopCountTimer LoopCountActionInternal(bool isPersistence, float interval, int loopCount, 558 | Action onComplete, Action onUpdate, Action onFinished, 559 | bool useRealTime, bool executeOnStart, Object autoDestroyOwner) 560 | { 561 | //Check 562 | if (loopCount <= 0) 563 | { 564 | SafeCall(onUpdate, 0); 565 | SafeCall(onComplete, 1); 566 | SafeCall(onFinished); 567 | return null; 568 | } 569 | 570 | var timer = new LoopCountTimer(isPersistence, interval, loopCount, onComplete, onUpdate, 571 | onFinished, useRealTime, executeOnStart, autoDestroyOwner); 572 | timer.Init(); 573 | return timer; 574 | } 575 | 576 | private static LoopCountTimer LoopCountActionInternal(bool isPersistence, float interval, int loopCount, 577 | Action onComplete, Action onUpdate, Action onFinished, 578 | UpdateMode updateMode, bool executeOnStart, Object autoDestroyOwner) 579 | { 580 | //Check 581 | if (loopCount <= 0) 582 | { 583 | SafeCall(onUpdate, 0); 584 | SafeCall(onComplete, 1); 585 | SafeCall(onFinished); 586 | return null; 587 | } 588 | 589 | var timer = new LoopCountTimer(isPersistence, interval, loopCount, onComplete, onUpdate, 590 | onFinished, updateMode, executeOnStart, autoDestroyOwner); 591 | timer.Init(); 592 | return timer; 593 | } 594 | 595 | #endregion 596 | 597 | #region Private Static Properties/Fields 598 | 599 | // responsible for updating all registered timers 600 | private static TimerManager _manager; 601 | 602 | #endregion 603 | 604 | #region Private/Protected Properties/Fields 605 | 606 | 607 | // whether the timer is in TimeManager 608 | private bool _isInManager; 609 | 610 | protected Action _onUpdate; 611 | protected float _startTime; 612 | private float _lastUpdateTime; 613 | 614 | // for pausing, we push the start time forward by the amount of time that has passed. 615 | // this will mess with the amount of time that elapsed when we're cancelled or paused if we just 616 | // check the start time versus the current world time, so we need to cache the time that was elapsed 617 | // before we paused/cancelled/autoDestroy 618 | private float? _timeElapsedBeforeCancel; 619 | private float? _timeElapsedBeforePause; 620 | private float? _timeElapsedBeforeAutoDestroy; 621 | 622 | private readonly LinkedListNode _linkedListNode; 623 | 624 | #endregion 625 | 626 | #region Constructor (use static method to create new timer) 627 | 628 | static Timer() 629 | { 630 | InitTimerManager(); 631 | } 632 | 633 | protected Timer(bool isPersistence, float duration, Action onUpdate, 634 | bool usesRealTime, Object autoDestroyOwner) 635 | : this(isPersistence, duration, onUpdate, GetUpdateMode(usesRealTime), autoDestroyOwner) 636 | { 637 | } 638 | 639 | protected Timer(bool isPersistence, float duration, Action onUpdate, 640 | UpdateMode updateMode, Object autoDestroyOwner) 641 | { 642 | this.isPersistence = isPersistence; 643 | this.duration = duration; 644 | this._onUpdate = onUpdate; 645 | 646 | this.updateMode = updateMode; 647 | 648 | this.autoDestroyOwner = autoDestroyOwner; 649 | this.hasAutoDestroyOwner = autoDestroyOwner != null; 650 | 651 | _linkedListNode = new LinkedListNode(this); 652 | } 653 | 654 | #endregion 655 | 656 | #region Private/Protected Methods 657 | 658 | private void Init() 659 | { 660 | //avoid virtual member call in constructor 661 | _startTime = GetWorldTime(); 662 | _lastUpdateTime = _startTime; 663 | Register(); 664 | OnInit(); 665 | } 666 | 667 | private void Register() 668 | { 669 | //no need to add 670 | if (_isInManager) return; 671 | _isInManager = true; 672 | _manager.Register(this); 673 | } 674 | 675 | protected float GetFireTime() 676 | { 677 | return _startTime + duration; 678 | } 679 | 680 | protected virtual float GetWorldTime() 681 | { 682 | switch (updateMode) 683 | { 684 | case UpdateMode.GameTime: 685 | return Time.time; 686 | case UpdateMode.UnscaledGameTime: 687 | return Time.unscaledTime; 688 | case UpdateMode.RealTime: 689 | return Time.realtimeSinceStartup; 690 | default: 691 | goto case UpdateMode.GameTime; 692 | } 693 | } 694 | 695 | protected virtual void OnInit() 696 | { 697 | } 698 | 699 | protected abstract void Update(); 700 | 701 | protected virtual void OnRestart() 702 | { 703 | } 704 | 705 | protected bool CheckUpdate() 706 | { 707 | if (isDone) return false; 708 | 709 | if (isPaused) 710 | { 711 | var curTime = GetWorldTime(); 712 | _startTime += curTime - _lastUpdateTime; 713 | _lastUpdateTime = curTime; 714 | return false; 715 | } 716 | 717 | _lastUpdateTime = GetWorldTime(); 718 | return true; 719 | } 720 | 721 | protected static void SafeCall(Action action) 722 | { 723 | if (action == null) return; 724 | try 725 | { 726 | action(); 727 | } 728 | catch (Exception e) 729 | { 730 | Debug.LogError(e); 731 | } 732 | } 733 | 734 | protected static void SafeCall(Action action, T arg) 735 | { 736 | if (action == null) return; 737 | try 738 | { 739 | action(arg); 740 | } 741 | catch (Exception e) 742 | { 743 | Debug.LogError(e); 744 | } 745 | } 746 | 747 | protected static TResult SafeCall(Func func) 748 | { 749 | if (func == null) return default; 750 | try 751 | { 752 | return func(); 753 | } 754 | catch (Exception e) 755 | { 756 | Debug.LogError(e); 757 | return default; 758 | } 759 | } 760 | 761 | protected static TResult SafeCall(Func func, T arg) 762 | { 763 | if (func == null) return default; 764 | try 765 | { 766 | return func(arg); 767 | } 768 | catch (Exception e) 769 | { 770 | Debug.LogError(e); 771 | return default; 772 | } 773 | } 774 | 775 | #endregion 776 | 777 | #region Manager Class (implementation detail, spawned automatically and updates all registered timers) 778 | 779 | /// 780 | /// Manages updating all the s that are running in the application. 781 | /// This will be instantiated the first time you create a timer -- you do not need to add it into the 782 | /// scene manually. 783 | /// 784 | private class TimerManager : MonoBehaviour 785 | { 786 | private readonly LinkedList 787 | _persistenceTimers = 788 | new LinkedList(); //can not be effected by Timer.xxAllRegisteredTimers() methods 789 | 790 | private readonly LinkedList _timers = new LinkedList(); 791 | 792 | // buffer adding timers so we don't edit a collection during iteration 793 | private readonly List _timersToAdd = new List(); 794 | private readonly List _persistenceTimersToAdd = new List(); 795 | 796 | public void CancelAllTimers() 797 | { 798 | foreach (Timer timer in _timers) 799 | { 800 | timer.Cancel(); 801 | timer._isInManager = false; 802 | } 803 | 804 | foreach (Timer timer in _timersToAdd) 805 | { 806 | timer.Cancel(); 807 | timer._isInManager = false; 808 | } 809 | 810 | _timers.Clear(); 811 | _timersToAdd.Clear(); 812 | } 813 | 814 | public void CancelAllTimersByOwner(Object owner) 815 | { 816 | if (!owner) return; 817 | CancelAllTimersByOwner(_timers, _timersToAdd, owner); 818 | CancelAllTimersByOwner(_persistenceTimers, _persistenceTimersToAdd, owner); 819 | } 820 | 821 | public void PauseAllTimers() 822 | { 823 | foreach (Timer timer in _timers) 824 | { 825 | timer.Pause(); 826 | } 827 | 828 | foreach (Timer timer in _timersToAdd) 829 | { 830 | timer.Pause(); 831 | } 832 | } 833 | 834 | public void ResumeAllTimers() 835 | { 836 | foreach (Timer timer in _timers) 837 | { 838 | timer.Resume(); 839 | } 840 | 841 | foreach (Timer timer in _timersToAdd) 842 | { 843 | timer.Resume(); 844 | } 845 | } 846 | 847 | public void Register(Timer timer) 848 | { 849 | if (!timer.isPersistence) 850 | _timersToAdd.Add(timer); 851 | else 852 | _persistenceTimersToAdd.Add(timer); 853 | } 854 | 855 | // update all the registered timers on every frame 856 | private void Update() 857 | { 858 | UpdateTimers(); 859 | UpdatePersistenceTimers(); 860 | } 861 | 862 | //Timer 863 | private void UpdateTimers() 864 | { 865 | UpdateTimersInternal(_timers, _timersToAdd); 866 | } 867 | 868 | //PersistenceTimer 869 | private void UpdatePersistenceTimers() 870 | { 871 | UpdateTimersInternal(_persistenceTimers, _persistenceTimersToAdd); 872 | } 873 | 874 | private static void UpdateTimersInternal(LinkedList timers, List timersToAdd) 875 | { 876 | int toAddCount = timersToAdd.Count; 877 | if (toAddCount > 0) 878 | { 879 | for (int i = 0; i < toAddCount; i++) 880 | timers.AddLast(timersToAdd[i]._linkedListNode); 881 | timersToAdd.Clear(); 882 | } 883 | 884 | var node = timers.First; 885 | while (node != null) 886 | { 887 | var timer = node.Value; 888 | timer.Update(); 889 | if (timer.isDone) 890 | { 891 | timer._isInManager = false; 892 | var toRemoveNode = node; 893 | node = node.Next; 894 | //remove 895 | timers.Remove(toRemoveNode); 896 | } 897 | else 898 | node = node.Next; 899 | } 900 | } 901 | 902 | private static void CancelAllTimersByOwner(LinkedList timers, List timersToAdd, Object owner) 903 | { 904 | var node = timers.First; 905 | while (node != null) 906 | { 907 | var timer = node.Value; 908 | if (!timer.isDone && timer.autoDestroyOwner == owner) 909 | { 910 | timer.Cancel(); 911 | timer._isInManager = false; 912 | var toRemoveNode = node; 913 | node = node.Next; 914 | //remove 915 | timers.Remove(toRemoveNode); 916 | } 917 | else 918 | node = node.Next; 919 | } 920 | 921 | for (int i = timersToAdd.Count - 1; i >= 0; i--) 922 | { 923 | var timer = timersToAdd[i]; 924 | if (!timer.isDone && timer.autoDestroyOwner != owner) continue; 925 | timer.Cancel(); 926 | timer._isInManager = false; 927 | //remove 928 | timersToAdd.RemoveAt(i); 929 | } 930 | } 931 | } 932 | 933 | #endregion 934 | 935 | } 936 | } 937 | -------------------------------------------------------------------------------- /Source/Timer.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 655b95530a761438792e7756b7bcb06c 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Source/TimerExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using GameUtil; 3 | using UnityEngine; 4 | using UpdateMode = GameUtil.Timer.UpdateMode; 5 | 6 | /// 7 | /// Contains extension methods related to s. 8 | /// 9 | public static class TimerExtensions 10 | { 11 | #region ComponentUseRealTime 12 | public static DelayTimer DelayAction(this Component component, float duration, Action onComplete, Action onUpdate = null, bool useRealTime = false) 13 | { 14 | return Timer.DelayAction(duration, onComplete, onUpdate, useRealTime, component); 15 | } 16 | 17 | public static LoopTimer LoopAction(this Component component, float interval, Action onComplete, Action onUpdate = null, 18 | bool useRealTime = false, bool executeOnStart = false) 19 | { 20 | return Timer.LoopAction(interval, onComplete, onUpdate, useRealTime, executeOnStart, component); 21 | } 22 | 23 | public static LoopUntilTimer LoopUntilAction(this Component component, float interval, Func loopUntil, Action onComplete, Action onUpdate = null, Action onFinished = null, 24 | bool useRealTime = false, bool executeOnStart = false) 25 | { 26 | return Timer.LoopUntilAction(interval, loopUntil, onComplete, onUpdate, onFinished, useRealTime, executeOnStart, component); 27 | } 28 | 29 | public static LoopCountTimer LoopCountAction(this Component component, float interval, int count, Action onComplete, Action onUpdate = null, Action onFinished = null, 30 | bool useRealTime = false, bool executeOnStart = false) 31 | { 32 | return Timer.LoopCountAction(interval, count, onComplete, onUpdate, onFinished, useRealTime, executeOnStart, component); 33 | } 34 | 35 | //Persistence 36 | public static DelayTimer PersistenceDelayAction(this Component component, float duration, Action onComplete, Action onUpdate = null, bool useRealTime = false) 37 | { 38 | return Timer.PersistenceDelayAction(duration, onComplete, onUpdate, useRealTime, component); 39 | } 40 | 41 | public static LoopTimer PersistenceLoopAction(this Component component, float interval, Action onComplete, Action onUpdate = null, 42 | bool useRealTime = false, bool executeOnStart = false) 43 | { 44 | return Timer.PersistenceLoopAction(interval, onComplete, onUpdate, useRealTime, executeOnStart, component); 45 | } 46 | 47 | public static LoopUntilTimer PersistenceLoopUntilAction(this Component component, float interval, Func loopUntil, Action onComplete, Action onUpdate = null, Action onFinished = null, 48 | bool useRealTime = false, bool executeOnStart = false) 49 | { 50 | return Timer.PersistenceLoopUntilAction(interval, loopUntil, onComplete, onUpdate, onFinished, useRealTime, executeOnStart, component); 51 | } 52 | 53 | public static LoopCountTimer PersistenceLoopCountAction(this Component component, float interval, int count, Action onComplete, Action onUpdate = null, Action onFinished = null, 54 | bool useRealTime = false, bool executeOnStart = false) 55 | { 56 | return Timer.PersistenceLoopCountAction(interval, count, onComplete, onUpdate, onFinished, useRealTime, executeOnStart, component); 57 | } 58 | #endregion 59 | 60 | #region GameObjectUseRealTime 61 | public static DelayTimer DelayAction(this GameObject gameObject, float duration, Action onComplete, Action onUpdate = null, bool useRealTime = false) 62 | { 63 | return Timer.DelayAction(duration, onComplete, onUpdate, useRealTime, gameObject); 64 | } 65 | 66 | public static LoopTimer LoopAction(this GameObject component, float interval, Action onComplete, Action onUpdate = null, 67 | bool useRealTime = false, bool executeOnStart = false) 68 | { 69 | return Timer.LoopAction(interval, onComplete, onUpdate, useRealTime, executeOnStart, component); 70 | } 71 | 72 | public static LoopUntilTimer LoopUntilAction(this GameObject component, float interval, Func loopUntil, Action onComplete, Action onUpdate = null, Action onFinished = null, 73 | bool useRealTime = false, bool executeOnStart = false) 74 | { 75 | return Timer.LoopUntilAction(interval, loopUntil, onComplete, onUpdate, onFinished, useRealTime, executeOnStart, component); 76 | } 77 | 78 | public static LoopCountTimer LoopCountAction(this GameObject component, float interval, int count, Action onComplete, Action onUpdate = null, Action onFinished = null, 79 | bool useRealTime = false, bool executeOnStart = false) 80 | { 81 | return Timer.LoopCountAction(interval, count, onComplete, onUpdate, onFinished, useRealTime, executeOnStart, component); 82 | } 83 | 84 | //Persistence 85 | public static DelayTimer PersistenceDelayAction(this GameObject component, float duration, Action onComplete, Action onUpdate = null, bool useRealTime = false) 86 | { 87 | return Timer.PersistenceDelayAction(duration, onComplete, onUpdate, useRealTime, component); 88 | } 89 | 90 | public static LoopTimer PersistenceLoopAction(this GameObject component, float interval, Action onComplete, Action onUpdate = null, 91 | bool useRealTime = false, bool executeOnStart = false) 92 | { 93 | return Timer.PersistenceLoopAction(interval, onComplete, onUpdate, useRealTime, executeOnStart, component); 94 | } 95 | 96 | public static LoopUntilTimer PersistenceLoopUntilAction(this GameObject component, float interval, Func loopUntil, Action onComplete, Action onUpdate = null, Action onFinished = null, 97 | bool useRealTime = false, bool executeOnStart = false) 98 | { 99 | return Timer.PersistenceLoopUntilAction(interval, loopUntil, onComplete, onUpdate, onFinished, useRealTime, executeOnStart, component); 100 | } 101 | 102 | public static LoopCountTimer PersistenceLoopCountAction(this GameObject component, float interval, int count, Action onComplete, Action onUpdate = null, Action onFinished = null, 103 | bool useRealTime = false, bool executeOnStart = false) 104 | { 105 | return Timer.PersistenceLoopCountAction(interval, count, onComplete, onUpdate, onFinished, useRealTime, executeOnStart, component); 106 | } 107 | #endregion 108 | 109 | #region Component 110 | public static DelayTimer DelayAction(this Component component, float duration, Action onComplete, Action onUpdate, UpdateMode updateMode) 111 | { 112 | return Timer.DelayAction(duration, onComplete, onUpdate, updateMode, component); 113 | } 114 | 115 | public static DelayFrameTimer DelayFrameAction(this Component component, int frame, Action onComplete, Action onUpdate = null) 116 | { 117 | return Timer.DelayFrameAction(frame, onComplete, onUpdate, component); 118 | } 119 | 120 | public static LoopTimer LoopAction(this Component component, float interval, Action onComplete, Action onUpdate, 121 | UpdateMode updateMode, bool executeOnStart = false) 122 | { 123 | return Timer.LoopAction(interval, onComplete, onUpdate, updateMode, executeOnStart, component); 124 | } 125 | 126 | public static LoopUntilTimer LoopUntilAction(this Component component, float interval, Func loopUntil, Action onComplete, Action onUpdate, Action onFinished, 127 | UpdateMode updateMode, bool executeOnStart = false) 128 | { 129 | return Timer.LoopUntilAction(interval, loopUntil, onComplete, onUpdate, onFinished, updateMode, executeOnStart, component); 130 | } 131 | 132 | public static LoopCountTimer LoopCountAction(this Component component, float interval, int count, Action onComplete, Action onUpdate, Action onFinished, 133 | UpdateMode updateMode, bool executeOnStart = false) 134 | { 135 | return Timer.LoopCountAction(interval, count, onComplete, onUpdate, onFinished, updateMode, executeOnStart, component); 136 | } 137 | 138 | //Persistence 139 | public static DelayTimer PersistenceDelayAction(this Component component, float duration, Action onComplete, Action onUpdate, UpdateMode updateMode) 140 | { 141 | return Timer.PersistenceDelayAction(duration, onComplete, onUpdate, updateMode, component); 142 | } 143 | 144 | public static DelayFrameTimer PersistenceDelayFrameAction(this Component component, int frame, Action onComplete, Action onUpdate = null) 145 | { 146 | return Timer.PersistenceDelayFrameAction(frame, onComplete, onUpdate, component); 147 | } 148 | 149 | public static LoopTimer PersistenceLoopAction(this Component component, float interval, Action onComplete, Action onUpdate, 150 | UpdateMode updateMode, bool executeOnStart = false) 151 | { 152 | return Timer.PersistenceLoopAction(interval, onComplete, onUpdate, updateMode, executeOnStart, component); 153 | } 154 | 155 | public static LoopUntilTimer PersistenceLoopUntilAction(this Component component, float interval, Func loopUntil, Action onComplete, Action onUpdate, Action onFinished, 156 | UpdateMode updateMode, bool executeOnStart = false) 157 | { 158 | return Timer.PersistenceLoopUntilAction(interval, loopUntil, onComplete, onUpdate, onFinished, updateMode, executeOnStart, component); 159 | } 160 | 161 | public static LoopCountTimer PersistenceLoopCountAction(this Component component, float interval, int count, Action onComplete, Action onUpdate, Action onFinished, 162 | UpdateMode updateMode, bool executeOnStart = false) 163 | { 164 | return Timer.PersistenceLoopCountAction(interval, count, onComplete, onUpdate, onFinished, updateMode, executeOnStart, component); 165 | } 166 | 167 | public static void CancelAllTimer(this Component component) 168 | { 169 | Timer.CancelAllRegisteredTimersByOwner(component); 170 | } 171 | #endregion 172 | 173 | #region GameObject 174 | public static DelayTimer DelayAction(this GameObject gameObject, float duration, Action onComplete, Action onUpdate, UpdateMode updateMode) 175 | { 176 | return Timer.DelayAction(duration, onComplete, onUpdate, updateMode, gameObject); 177 | } 178 | 179 | public static DelayFrameTimer DelayFrameAction(this GameObject component, int frame, Action onComplete, Action onUpdate = null) 180 | { 181 | return Timer.DelayFrameAction(frame, onComplete, onUpdate, component); 182 | } 183 | 184 | public static LoopTimer LoopAction(this GameObject component, float interval, Action onComplete, Action onUpdate, 185 | UpdateMode updateMode, bool executeOnStart = false) 186 | { 187 | return Timer.LoopAction(interval, onComplete, onUpdate, updateMode, executeOnStart, component); 188 | } 189 | 190 | public static LoopUntilTimer LoopUntilAction(this GameObject component, float interval, Func loopUntil, Action onComplete, Action onUpdate, Action onFinished, 191 | UpdateMode updateMode, bool executeOnStart = false) 192 | { 193 | return Timer.LoopUntilAction(interval, loopUntil, onComplete, onUpdate, onFinished, updateMode, executeOnStart, component); 194 | } 195 | 196 | public static LoopCountTimer LoopCountAction(this GameObject component, float interval, int count, Action onComplete, Action onUpdate, Action onFinished, 197 | UpdateMode updateMode, bool executeOnStart = false) 198 | { 199 | return Timer.LoopCountAction(interval, count, onComplete, onUpdate, onFinished, updateMode, executeOnStart, component); 200 | } 201 | 202 | //Persistence 203 | public static DelayTimer PersistenceDelayAction(this GameObject component, float duration, Action onComplete, Action onUpdate, UpdateMode updateMode) 204 | { 205 | return Timer.PersistenceDelayAction(duration, onComplete, onUpdate, updateMode, component); 206 | } 207 | 208 | public static DelayFrameTimer PersistenceDelayFrameAction(this GameObject component, int frame, Action onComplete, Action onUpdate = null) 209 | { 210 | return Timer.PersistenceDelayFrameAction(frame, onComplete, onUpdate, component); 211 | } 212 | 213 | public static LoopTimer PersistenceLoopAction(this GameObject component, float interval, Action onComplete, Action onUpdate, 214 | UpdateMode updateMode, bool executeOnStart = false) 215 | { 216 | return Timer.PersistenceLoopAction(interval, onComplete, onUpdate, updateMode, executeOnStart, component); 217 | } 218 | 219 | public static LoopUntilTimer PersistenceLoopUntilAction(this GameObject component, float interval, Func loopUntil, Action onComplete, Action onUpdate, Action onFinished, 220 | UpdateMode updateMode, bool executeOnStart = false) 221 | { 222 | return Timer.PersistenceLoopUntilAction(interval, loopUntil, onComplete, onUpdate, onFinished, updateMode, executeOnStart, component); 223 | } 224 | 225 | public static LoopCountTimer PersistenceLoopCountAction(this GameObject component, float interval, int count, Action onComplete, Action onUpdate, Action onFinished, 226 | UpdateMode updateMode, bool executeOnStart = false) 227 | { 228 | return Timer.PersistenceLoopCountAction(interval, count, onComplete, onUpdate, onFinished, updateMode, executeOnStart, component); 229 | } 230 | 231 | public static void CancelAllTimer(this GameObject component) 232 | { 233 | Timer.CancelAllRegisteredTimersByOwner(component); 234 | } 235 | #endregion 236 | } 237 | -------------------------------------------------------------------------------- /Source/TimerExtensions.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: cb8a45204e31641b38b1c01aacea5879 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | --------------------------------------------------------------------------------