Keeping track of time

pyglet’s clock module provides functionality for scheduling functions for periodic or one-shot future execution and for calculating and displaying the application frame rate.

Calling functions periodically

pyglet applications begin execution with:

pyglet.app.run()

Once called, this function doesn’t return until the application windows have been closed. This may leave you wondering how to execute code while the application is running.

Typical applications need to execute code in only three circumstances:

  • A user input event (such as a mouse movement or key press) has been generated. In this case the appropriate code can be attached as an event handler to the window.
  • An animation or other time-dependent system needs to update the position or parameters of an object. We’ll call this a “periodic” event.
  • A certain amount of time has passed, perhaps indicating that an operation has timed out, or that a dialog can be automatically dismissed. We’ll call this a “one-shot” event.

To have a function called periodically, for example, once every 0.1 seconds:

def update(dt):
    # ...
pyglet.clock.schedule_interval(update, 0.1)

The dt parameter gives the number of seconds (due to latency, load and timer inprecision, this might be slightly more or less than the requested interval).

Scheduling functions with a set interval is ideal for animation, physics simulation, and game state updates. pyglet ensures that the application does not consume more resources than necessary to execute the scheduled functions in time.

Rather than “limiting the frame rate”, as required in other toolkits, simply schedule all your update functions for no less than the minimum period your application or game requires. For example, most games need not run at more than 60Hz (60 times a second) for imperceptibly smooth animation, so the interval given to schedule_interval would be 1/60.0 (or more).

If you are writing a benchmarking program or otherwise wish to simply run at the highest possible frequency, use schedule:

def update(dt):
    # ...
pyglet.clock.schedule(update)

By default pyglet window buffer swaps are synchronised to the display refresh rate, so you may also want to disable set_vsync.

For one-shot events, use schedule_once:

def dismiss_dialog(dt):
    # ...

# Dismiss the dialog after 5 seconds.
pyglet.clock.schedule_once(dismiss_dialog, 5.0)

To stop a scheduled function from being called, including cancelling a periodic function, use pyglet.clock.unschedule.

Animation techniques

Every scheduled function takes a dt parameter, giving the actual “wall clock” time that passed since the previous invocation (or the time the function was scheduled, if it’s the first period). This parameter can be used for numerical integration.

For example, a non-accelerating particle with velocity v will travel some distance over a change in time dt. This distance is calculated as v * dt. Similarly, a particle under constant acceleration a will have a change in velocity of a * dt.

The following example demonstrates a simple way to move a sprite across the screen at exactly 10 pixels per second:

sprite = pyglet.sprite.Sprite(image)
sprite.dx = 10.0

def update(dt):
    sprite.x += sprite.dx * dt
pyglet.clock.schedule_interval(update, 1/60.0) # update at 60Hz

This is a robust technique for simple animation, as the velocity will remain constant regardless of the speed or load of the computer.

Some examples of other common animation variables are given in the table below.

Animation parameter Distance Velocity
Rotation Degrees Degrees per second
Position Pixels Pixels per second
Keyframes Frame number Frames per second

The frame rate

Game performance is often measured in terms of the number of times the display is updated every second; that is, the frames-per-second or FPS. You can determine your application’s FPS with a single function call:

pyglet.clock.get_fps()

The value returned is more useful than simply taking the reciprocal of dt from a period function, as it is averaged over a sliding window of several frames.

Displaying the frame rate

A simple way to profile your application performance is to display the frame rate while it is running. Printing it to the console is not ideal as this will have a severe impact on performance. pyglet provides the ClockDisplay class for displaying the frame rate with very little effort:

fps_display = pyglet.clock.ClockDisplay()

@window.event
def on_draw():
    window.clear()
    fps_display.draw()

By default the frame rate will be drawn in the bottom-right corner of the window in a semi-translucent large font. See the ClockDisplay documentation for details on how to customise this, or even display another clock value (such as the current time) altogether.

User-defined clocks

The default clock used by pyglet uses the system clock to determine the time (i.e., time.time()). Separate clocks can be created, however, allowing you to use another time source. This can be useful for implementing a separate “game time” to the real-world time, or for synchronising to a network time source or a sound device.

Each of the clock functions are aliases for the methods on a global instance of clock.Clock. You can construct or subclass your own Clock, which can then maintain its own schedule and framerate calculation. See the class documentation for more details.