Clocks

Often when writing a game, you will want to schedule some game event to occur at a later time. For example, we may want a big boss alien to appear after 60 seconds. Or perhaps a power-up will appear every 20 seconds.

There are also cases where you want to delay some action for a shorter period. For example you might have a laser weapon that takes 1 second to charge up.

We can use the clock object to schedule a function to happen in the future.

Let’s start by defining a function fire_laser that we want to run in the future:

def fire_laser():
    lasers.append(player.pos)

Then when the fire button is pressed, we will ask the clock to call it for us after exactly 1 second:

def on_mouse_down():
    clock.schedule(fire_laser, 1.0)

Note that fire_laser is the function itself; without parentheses, it is not being called here! The clock will call it for us.

(It is a good habit to write out times in seconds with a decimal point, like 1.0. This makes it more obvious when you are reading it back, that you are referring to a time value and not a count of things.)

clock provides the following useful methods:

class Clock
schedule(callback, delay, strong=False)

Schedule callback to be called after the given delay.

Repeated calls will schedule the callback repeatedly.

Parameters
  • callback – A callable that takes no arguments.

  • delay – The delay, in seconds, before the function should be called.

  • strong – Hold a strong reference to callback.

schedule_unique(callback, delay, strong=False)

Schedule callback to be called once after the given delay.

If callback was already scheduled, cancel and reschedule it. This applies also if it was scheduled multiple times: after calling schedule_unique, it will be scheduled exactly once.

Parameters
  • callback – A callable that takes no arguments.

  • delay – The delay, in seconds, before the function should be called.

  • strong – Hold a strong reference to callback.

schedule_interval(callback, interval, strong=False)

Schedule callback to be called repeatedly.

Parameters
  • callback – A callable that takes no arguments.

  • interval – The interval in seconds between calls to callback.

  • strong – Hold a strong reference to callback.

each_tick(callback, strong=False)

Schedule callback to be called every tick. The callback in this case is required to accept a parameter dt which is the time in seconds since the last tick.

Parameters
  • callback – A one argument callable.

  • strong – Hold a strong reference to callback.

call_soon(callback)

Schedule callback to be called on the next tick. Unlike most other clock methods, callback will be strongly referenced here.

Parameters

callback – A one argument callable.

unschedule(callback)

Unschedule callback if it has been previously scheduled (either because it has been scheduled with schedule() and has not yet been called, or because it has been scheduled to repeat with schedule_interval() or each_tick().

coro

Interface to asynchronous programming using coroutines, linked to this clock. See Coroutines.

create_sub_clock(rate=1.0) SubClock

Create a new clock that ticks when this one ticks, but potentially at a different rate.

Note that by default the wasabi2d clock only holds weak references to each callback you give it. It will not fire scheduled events if the objects and methods are not referenced elsewhere. This can help prevent the clock keeping objects alive and continuing to fire unexpectedly after they are otherwise dead.

Pass strong=True if you want the clock to hold a strong reference instead.

Subclocks

One clock is often enough for simple games, and Wasabi2D’s built-in clock, available as wasabi2d.clock, is all you need. It measures time in real time and is ticked by Wasabi2D’s event loop.

But many games will need a second clock that runs at an independent rate, and which can be paused. For example:

  • All gameplay needs be paused while the menu is visible

  • The menu runs with animations in real time even while gameplay is paused

You can also create slow-motion effects where the game slows down, but some animations (maybe information like health bars and pickups) should update at their normal rate.

A clock that runs at a fraction of a parent clock (perhaps most often the default, real time Clock) is a subclock and has extra methods that let you control the rate at which it runs, or pause it independently.

Create a subclock with Clock.create_sub_clock() on the clock you want it to be attached to.

class SubClock

A clock that runs at some fraction of the rate of a parent clock.

paused

A boolean. Set this to True to stop this clock from updating.

rate

A float. The fraction of the speed of parent clock. 0 would be frozen, 1.0 is full speed. A number between 0 and 1 is slow motion. A number greater than 1.0 would be faster motion.

slowmo(rate)

A context manager to enter slow motion for the duration of a context.

This only makes sense when used with coroutines that await during the context. For example:

async def slow_mo_explosion():
    with clock.slowmo(0.5):
        await explosion()

Subclocks can have their own subclocks.