Time Integration

I find myself writing cooldowns and countdowns all the time. Bullets can only fire so fast, bombs explode after five seconds, enemies spawn every 10-15 seconds. Every time I do it, I write the same boilerplate in the initialization:

goomba.cooldown_max = 5 // 5 seconds to cool down
goomba.cooldown_timer = goomba.cooldown_max

and the same boilerplate in the update function:

if goomba.cooldown_timer > 0:
goomba.cooldown_timer -= time_step
if goomba.cooldown_timer < 0:
// insert end behavior here

and somewhere, I activate this behavior (in response to a keypress, or proximit, or contact):

goomba.cooldown_timer = goomba.cooldown_max

I do this kind of thing so often that I feel like it should be one of the basic functionalities offered when I'm trying to describe game entity behavior.

// initialization
goomba.shot_timer = new CooldownTimer(length=5s, on_end=function() {...})
// update functionality should be taken care of automatically, but if not:
goomba.shot_timer.step(time_step)
// activating the timer:
goomba.shot_timer.start()

Now, wasn't that easy?

Of course, that's a pretty simple case! There are obvious extensions, though:

goomba.blink_timer = new EndlessTimer()
goomba.blink_timer.interval = 5s
goomba.blink_timer.at_progress(0%, goomba.change_color) // change color at the start of each interval
goomba.blink_timer.at_progress(50%, goomba.take_step) // take a step once every interval halfway through

And now making timed behavior for our goomba is easy! We can even speed up the goomba easily: goomba.blink_timer.interval = 3s

Ideally, you don't need to even specify when to step your timers - that should be taken care of automatically. Of course, that means we'd want to register these timers instead of simply declaring them as a member - but maybe that's a matter of a grander architectural problem.

Although! If we do let the developer take care of stepping the timers, then we can also use it for things that aren't time-dependent:

player.limit_bar = new Meter(length=100) // general verison of the CooldownTimer
player.on('hit by enemy', player.limit_bar.step)
player.limit_bar.at_progress(100%, player.limit_break)

And now we've got a way for limit breaks to engage. Assuming there's a pre-existing event system and everything is architected carefully, it's now incredibly easy to fill meters in response to events.