1 /** 2 Tweening 3 4 Copyright: (c) Enalye 2019 5 License: Zlib 6 Authors: Enalye 7 */ 8 9 module atelier.core.timer; 10 11 import atelier.common; 12 13 /** 14 Simple updatable timer. \ 15 Start with start() and update with update(Deltatime). \ 16 Returns a value between 0 and 1. 17 */ 18 struct Timer { 19 /// Change the way Timer behave. \ 20 /// once: Will run from 0 to 1 in one duration then stop. \ 21 /// reverse: Will run from 1 to 0 in one duration then stop. \ 22 /// loop: Will run from 0 to 1 in one duration then restart from 0 again, etc. \ 23 /// loopReverse: Will run from 1 to 0 in one duration then restart from 1 again, etc. \ 24 /// bounce: Will run from 0 to 1 in one duration then from 1 to 0, etc. \ 25 /// bounceReverse: Will run from 1 to 0 in one duration then from 0 to 1, etc. 26 enum Mode { 27 once, 28 reverse, 29 loop, 30 loopReverse, 31 bounce, 32 bounceReverse 33 } 34 35 private { 36 float _time = 0f, _duration = 1f; 37 bool _isRunning = false, _isReversed = false; 38 Mode _mode = Mode.once; 39 } 40 41 @property { 42 /// The relative time elapsed between 0 and 1. 43 float value01() const { 44 return _time; 45 } 46 47 /// Time elapsed between 0 and the max duration. 48 float value() const { 49 return _time * _duration; 50 } 51 52 /// Duration in seconds from witch the timer goes from 0 to 1 (framerate dependent). \ 53 /// Only positive non-null values. 54 float duration() const { 55 return _duration; 56 } 57 /// Ditto 58 float duration(float v) { 59 return _duration = v; 60 } 61 62 /// Is the timer currently running ? 63 bool isRunning() const { 64 return _isRunning; 65 } 66 67 /// Current behavior of the timer. 68 Mode mode() const { 69 return _mode; 70 } 71 /// Ditto 72 Mode mode(Mode v) { 73 return _mode = v; 74 } 75 } 76 77 /// Immediatly starts the timer. \ 78 /// Note that loop and bounce behaviours will never stop until you tell him to. 79 void start() { 80 _isRunning = true; 81 reset(); 82 } 83 84 /// Immediatly starts the timer with the specified running time. \ 85 /// Note that loop and bounce behaviours will never stop until you tell him to. 86 void start(float duration_) { 87 _isRunning = true; 88 duration(duration_); 89 reset(); 90 } 91 92 /// Immediatly stops the timer and resets it. 93 void stop() { 94 _isRunning = false; 95 reset(); 96 } 97 98 /// Interrupts the timer without resetting it. 99 void pause() { 100 _isRunning = false; 101 } 102 103 /// Resumes the timer from where it was stopped. 104 void resume() { 105 _isRunning = true; 106 } 107 108 /// Goes back to starting settings. 109 void reset() { 110 final switch (_mode) with (Mode) { 111 case once: 112 _time = 0f; 113 _isReversed = false; 114 break; 115 case reverse: 116 _time = 1f; 117 _isReversed = false; 118 break; 119 case loop: 120 _time = 0f; 121 _isReversed = false; 122 break; 123 case loopReverse: 124 _time = 1f; 125 _isReversed = false; 126 break; 127 case bounce: 128 _time = 0f; 129 _isReversed = false; 130 break; 131 case bounceReverse: 132 _time = 1f; 133 _isReversed = false; 134 break; 135 } 136 } 137 138 /// Update with the current deltatime (~1) 139 /// If you don't call update, the timer won't advance. 140 void update(float deltaTime) { 141 if (!_isRunning) 142 return; 143 if (_duration <= 0f) { 144 _time = _isReversed ? 0f : 1f; 145 _isRunning = false; 146 return; 147 } 148 const float stepInterval = deltaTime / (getNominalFPS() * _duration); 149 final switch (_mode) with (Mode) { 150 case once: 151 if (_time < 1f) 152 _time += stepInterval; 153 if (_time >= 1f) { 154 _time = 1f; 155 _isRunning = false; 156 } 157 break; 158 case reverse: 159 if (_time > 0f) 160 _time -= stepInterval; 161 if (_time <= 0f) { 162 _time = 0f; 163 _isRunning = false; 164 } 165 break; 166 case loop: 167 if (_time < 1f) 168 _time += stepInterval; 169 if (_time >= 1f) 170 _time = (_time - 1f) + stepInterval; 171 break; 172 case loopReverse: 173 if (_time > 0f) 174 _time -= stepInterval; 175 if (_time <= 0f) 176 _time = (1f - _time) - stepInterval; 177 break; 178 case bounce: 179 if (_isReversed) { 180 if (_time > 0f) 181 _time -= stepInterval; 182 if (_time <= 0f) { 183 _time = -(_time - stepInterval); 184 _isReversed = false; 185 } 186 } 187 else { 188 if (_time < 1f) 189 _time += stepInterval; 190 if (_time >= 1f) { 191 _time = 1f - ((_time - 1f) + stepInterval); 192 _isReversed = true; 193 } 194 } 195 break; 196 case bounceReverse: 197 if (_isReversed) { 198 if (_time < 1f) 199 _time += stepInterval; 200 if (_time >= 1f) { 201 _time = 1f - ((_time - 1f) + stepInterval); 202 _isReversed = false; 203 } 204 } 205 else { 206 if (_time > 0f) 207 _time -= stepInterval; 208 if (_time <= 0f) { 209 _time = -(_time - stepInterval); 210 _isReversed = true; 211 } 212 } 213 break; 214 } 215 } 216 }