class Game(object): def __init__(self): self.screen = pygame.display.set_mode((800,600)) self.screen_rect = self.screen.get_rect() self.font = pygame.font.SysFont(None, 16) self.clock = GameClock( 30, 120, update_callback=self.update, frame_callback=self.draw, paused_callback=self.pause, ) self.draw_line = pygame.draw.line self.ucolor = Color('grey') self.dcolor = Color('white') self.pcolor = Color('blue') self.running = True self.paused = False self.ball = pygame.Surface((30,30)) self.ball.fill(Color(255,0,0)) self.ball_start = 300 self.ball_rect = self.ball.get_rect(x=self.ball_start) self.ball_from = self.ball_start self.ball_to = self.ball_start self.elapsed = 0. self.nupdates = 0 self.n10updates = 0 self.utime = pygame_time() self.dtime = pygame_time() self.ptime = pygame_time() self.uerror = 0 self.derror = 0 self.umax = 0 self.dmax = 0 self.ptxt = None self.msgs = [] # Recur every second self.clock.schedule_interval(self.per_second, 1.) # Recur every 10 seconds self.clock.schedule_interval(self.per_10_second, 10.) # Recur every second, for two iterations self.clock.schedule_interval(self.recur, 1., 2) def run(self): clock = self.clock while self.running: clock.tick() def update(self, dt): # Track accuracy. For example, at 30 ups, each update+frames set # should not exceed 33 ms. t = pygame_time() utime = self.utime mydt = (t - utime)/1000. self.uerror += dt - mydt self.utime = t for e in pygame.event.get(): if e.type == KEYDOWN: self.on_key_down(e) self.ball_from = self.ball_to self.ball_to += dt * 200 ## waste many ms / update if SIM_LOAD: pygame.time.wait(self.umax) def draw(self, interp): t = pygame_time() # self.screen.fill((0,0,0)) x = self.screen_rect.centerx y = 10 error = min(max(self.uerror/1000,-100),100) self.draw_line(self.screen, self.ucolor, (x,y), (x+error,y), 5) y += 10 txt = self.font.render('DT Update ms error: {0:+0.3f}'.format(self.uerror), True, self.ucolor) r = txt.get_rect(centerx=x,top=y) self.screen.blit(txt, r) y += 20 self.ball_rect.y = y dx = (self.ball_to - self.ball_from) * self.clock.interpolate self.ball_rect.centerx = self.ball_from + dx self.screen.blit(self.ball, self.ball_rect) for i,msg in enumerate(self.msgs): r = msg.get_rect(x=3) r.y = 3 + (3+r.h) * i self.screen.blit(msg, r) pygame.display.flip() ## waste many ms / frame if SIM_LOAD: pygame.time.wait(self.dmax) def pause(self): for e in pygame.event.get(): if e.type == KEYDOWN: self.on_key_down(e) msg = 'Time is PAUSED' if self.paused else 'Time is Running' self.msgs[0] = self.font.render(msg, True, Color('grey')) self.draw(self.clock.interpolate) def per_second(self, *args): # flip the ball and performance meter every second self.nupdates += 1 del self.msgs[:] for msg in ( 'Time is PAUSED' if self.paused else 'Time is Running', '{0:d} second elapsed'.format(self.nupdates), '{0:d} 10-second elapsed'.format(self.n10updates), '{0:.1f} / {1:.1f} ups/max'.format(self.clock.ups, self.clock.max_ups), '{0:.1f} / {1:.1f} fps/max'.format(self.clock.fps, self.clock.max_fps), '{0:d} update waste ms'.format(self.umax), '{0:d} draw waste ms'.format(self.dmax), '{0:d} use wait'.format(self.clock.use_wait), '{0:f} DT update'.format(self.clock.dt_update), '{0:f} cost of update'.format(self.clock.cost_of_update), '{0:f} DT frame'.format(self.clock.dt_frame), '{0:f} cost of frame'.format(self.clock.cost_of_frame), ): self.msgs.append(self.font.render(msg, True, Color('grey'))) self.ball_from = self.ball_start self.ball_to = self.ball_from + self.clock.dt_update * 200 def per_10_second(self, *args): self.n10updates += 10 msg = '{0:d} 10-second elapsed'.format(self.n10updates) self.msgs[2] = self.font.render(msg, True, Color('grey')) def recur(self, *args): print 'RECUR' def on_key_down(self, e): if e.key == K_SPACE: # toggle max FPS: 0 vs. 60 self.clock.max_fps = 0 if self.clock.max_fps else 120 if DEBUG: print '\n--- max_fps:{0:d} ---'.format(self.clock.max_fps) elif e.key == K_UP: if e.mod & KMOD_SHIFT: # increment simulated update load self.umax += 5 if DEBUG: print '\n--- umax +5:{0:d} ---'.format(self.umax) else: # increment simulated draw load self.dmax += 5 if DEBUG: print '\n--- dmax +5:{0:d} ---'.format(self.dmax) elif e.key == K_DOWN: if e.mod & KMOD_SHIFT and self.umax: # decrement simulated update load self.umax -= 5 if DEBUG: print '\n--- umax -5:{0:d} ---'.format(self.umax) elif self.dmax: # decrement simulated draw load self.dmax -= 5 if DEBUG: print '\n--- dmax -5:{0:d} ---'.format(self.dmax) elif e.key == K_d: # toggle debug messages gameclock.DEBUG = not gameclock.DEBUG if gameclock.DEBUG: print '\n--- debug on ---' else: print '\n--- debug off ---' elif e.key == K_p: if self.paused: # pause clock self.paused = False self.clock.resume() else: # unpause clock self.paused = True self.clock.pause() elif e.key == K_w: # toggle use_wait self.clock.use_wait = not self.clock.use_wait if self.clock.use_wait: if DEBUG: print '\n--- wait on---' else: if DEBUG: print '\n--- wait off ---' elif e.key == K_ESCAPE: quit()