application event loop

48 views
Skip to first unread message

Simon Wittber

unread,
Mar 7, 2008, 2:03:40 AM3/7/08
to pyglet-users
I've been testing out the new 1.1 stuff and am very impressed so far.
Nice work! However, I have noticed one problem with the application
event loop.

The programming guide suggests that this code is an effective way to
schedule an update at 60hz.


def update(dt):
pass
clock.schedule_interval(update, 1/60.0)


Using this technique there is a 0.007135 standard deviation on the
times passed to update. Using the older technique:


while not window.has_exit:
dt = pyglet.clock.tick()
update(dt)
window.dispatch_events()
draw()
window.flip()


produces a standard deviation of 0.000748, which is better than the
new method, thought not perfect.

Why should we worry about this? It important to have a fixed
simulation step when dealing with physics engines and other similar
simulations. There will also be the side effect of jittery animation
if frames get skipped.

I suggest that to fix this, the loop could do something like this
(taken from the mainloop package and abbreviated):


def run(max_frame_time=0.2, step=1.0/60):
now = current_time() - step
while True:
dispatch_events()
T = current_time()

#this does frame skipping if needed
if T-now > max_frame_time:
now = T - step

#this calls the update function as many times as needed.
(usually 0 times or once)
idle = True
while(T-now >= step):
update(step)
now += step
idle = False
if idle: rest_the_cpu()

#calculate how far we are through a step(%)
P = (T-now)/step_size
self.on_draw(P)


The above code does a few things. It provides an update event with a
constant time delta argument, and therefore a standard deviation of
0!

It also provided an argument to the on_draw event which is the
percentage between steps. This allows the on_draw event to interpolate
between steps. This gives the best framerate possible while preserving
a fixed time step. You could theoretically run the loop at 2 updates
per second, while keeping the animation running at 60 fps.

I hope I've made some sense. Any thoughts on the above?

-Simon Wittber



Alex Holkner

unread,
Mar 7, 2008, 2:43:11 AM3/7/08
to pyglet...@googlegroups.com

There's no need for this to be in pyglet's event loop; it can be
layered on top of the provided clock.schedule_interval(). I'd
envisage something like::

runloop = FixedRunloop(update, step=1/60., max_step=0.2)
# FixedRunloop schedules its internal update method on
# clock; calls update only at fixed intervals.

def on_draw():
# Get interpolation/extrapolation fraction.
p = runloop.get_step_fraction()

While some applications require a fixed timestep, others only desire
it (e.g., simple integration), and others have no need for it (e.g.,
path controlled animation). Most applications would not want to deal
with the complexity of drawing a scene interpolated between two
states.

Alex.

Reply all
Reply to author
Forward
0 new messages