This class implements a generator, which returns consecutive floats which are incremented by a speed * (time between calls).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | import time
class GovernedRange(object):
def __init__(self, low, high, speed=1):
"""
Returns a range of floats, where each consecutive number is
incremented at a speed * time between iterations, rather than
a set value.
low: start of range
high: top of range
speed: amount to increment, per second.
"""
self.speed = float(speed)
self.low = float(low)
self.high = float(high)
self._i = self.low
self._t = time.time()
def __iter__(self):
while True:
yield self.next()
def next(self):
speed = float(self.speed)
inc = speed * (time.time() - self._t)
i = self._i
i += inc
self._t = time.time()
if i >= self.high: raise StopIteration
self._i = i
return i
for x in GovernedRange(1,5,speed=1):
print x
time.sleep(0.1)
|
I use this recipe to create linear ramps in realtime simulations. This is especially useful for creating animated sprite translations, rotations and other transformations regardless of the client machine's framerate.
The speed attribute can be changed by another GovernedRange, which will provide smooth, linear accelerations.
I also find it useful for providing smooth, framerate independent frame advancement of sprite strip animations.
Various improvements. The code is faster and more concise when expressed as a generator rather than as a class based iterator. Most of the gains arise from using local variables rather than instance variables.
On Windows platforms, timer resolution is improved by using time.clock instead of time.time (taking a lesson from the timeit module).
Readability is further improved by use of clearer variable names.
Acceleration. The last recipe can be modified so that speed gets multiplied by a global variable to allow for smooth accelerations.
Acceleration, with global variable. This is actually the reason I used a class, rather than a generator.
If I have multiple GovernedRange generators , I would need multiple global variables. Using a class to implement the GovernedRange creates a more usuable, encapsulated object.