robolib.utils.clock
clock.py - clock used for physics with fixed DT in main loops Usage: clock = Clock(dt=1 / FPS, max_ticks=MAX_SUBTICKS_PER_RENDER_TICK) # max_ticks is for 'spiral of death' (e.g. use 3-5) while True: # main loop clock.wait_and_tick() ... io stuff ... for _ in clock.drain(): ... physics loop ... ... render loop ...
1""" 2clock.py - clock used for physics with fixed DT in main loops 3Usage: 4clock = Clock(dt=1 / FPS, max_ticks=MAX_SUBTICKS_PER_RENDER_TICK) # max_ticks is for 'spiral of death' (e.g. use 3-5) 5while True: # main loop 6 clock.wait_and_tick() 7 ... io stuff ... 8 for _ in clock.drain(): 9 ... physics loop ... 10 ... render loop ... 11""" 12import time 13 14class Clock: 15 """clock used for physics with fixed DT in main loops""" 16 17 def __init__(self, dt: float, max_ticks: int): 18 self.dt = dt 19 self.max_ticks = max_ticks 20 self.prev_time = time.perf_counter() 21 self.accumulator = 0 22 self.tick_count = -1 23 24 def tick(self): 25 """tick once by adding the delta between prev frame and now""" 26 now = time.perf_counter() 27 frame_time = now - self.prev_time 28 self.prev_time = now 29 self.accumulator += frame_time 30 self.tick_count += 1 31 32 def drain(self): 33 """drain the accumulator. in main loop: for _ in clock.drain(): ...""" 34 n_ticks = 0 35 while self.accumulator >= self.dt and n_ticks < self.max_ticks: 36 yield 37 self.accumulator -= self.dt 38 n_ticks += 1 39 self.accumulator = min(self.accumulator, self.dt) # Drop residual debt instead of it piling up across frames 40 41 def wait(self): 42 """waits the leftover time in case the previous tick ran too fast to maintain consistent FPS""" 43 time.sleep(max(self.dt - (time.perf_counter() - self.prev_time), 0)) 44 45 def wait_and_tick(self): 46 """calls wait() then tick(). Put this at the beginning of the main loop :)""" 47 self.wait() 48 self.tick()
class
Clock:
15class Clock: 16 """clock used for physics with fixed DT in main loops""" 17 18 def __init__(self, dt: float, max_ticks: int): 19 self.dt = dt 20 self.max_ticks = max_ticks 21 self.prev_time = time.perf_counter() 22 self.accumulator = 0 23 self.tick_count = -1 24 25 def tick(self): 26 """tick once by adding the delta between prev frame and now""" 27 now = time.perf_counter() 28 frame_time = now - self.prev_time 29 self.prev_time = now 30 self.accumulator += frame_time 31 self.tick_count += 1 32 33 def drain(self): 34 """drain the accumulator. in main loop: for _ in clock.drain(): ...""" 35 n_ticks = 0 36 while self.accumulator >= self.dt and n_ticks < self.max_ticks: 37 yield 38 self.accumulator -= self.dt 39 n_ticks += 1 40 self.accumulator = min(self.accumulator, self.dt) # Drop residual debt instead of it piling up across frames 41 42 def wait(self): 43 """waits the leftover time in case the previous tick ran too fast to maintain consistent FPS""" 44 time.sleep(max(self.dt - (time.perf_counter() - self.prev_time), 0)) 45 46 def wait_and_tick(self): 47 """calls wait() then tick(). Put this at the beginning of the main loop :)""" 48 self.wait() 49 self.tick()
clock used for physics with fixed DT in main loops
def
tick(self):
25 def tick(self): 26 """tick once by adding the delta between prev frame and now""" 27 now = time.perf_counter() 28 frame_time = now - self.prev_time 29 self.prev_time = now 30 self.accumulator += frame_time 31 self.tick_count += 1
tick once by adding the delta between prev frame and now
def
drain(self):
33 def drain(self): 34 """drain the accumulator. in main loop: for _ in clock.drain(): ...""" 35 n_ticks = 0 36 while self.accumulator >= self.dt and n_ticks < self.max_ticks: 37 yield 38 self.accumulator -= self.dt 39 n_ticks += 1 40 self.accumulator = min(self.accumulator, self.dt) # Drop residual debt instead of it piling up across frames
drain the accumulator. in main loop: for _ in clock.drain(): ...