As Scathe noted over here, there's not a proper/easy-to-use Timers API built into PICO-8. Turns out it's not too hard to build one, though, so I took up the task.
The cartridge which you can play above just counts to 10. I've reproduced all the code here:
The actual "Timers API" is between "-- start timers code" and "-- end timers code." It might seem a bit verbose; take what you need and leave the rest.
This should be robust enough to meet any typical needs. The main weakness right now is that you can't have multiple step or end callbacks, and you can't add callbacks after the timer is initialized.
API specification:
This looks good! It's already possible to add/remove/change callbacks after timer creation by modifying step_fn/end_fn directly, and if you needed to call multiple functions on one timer then you could just handle that yourself within the callback.
One gotcha is that time() will overflow once it gets past 32768 seconds, so on the off-chance someone leaves a cart going for 9 hours then the timers would break x) This could be caught with a check in update_timer(), but probably not worth the symbols.
EDIT: one alternative could be to pass the timer itself as a parameter to the callback, instead of (or as well as) elapsed and length. That would make it easier to stop/restart the timer from within the callback while still allowing callbacks to be shared across timers.
Hey great to see the post inspired someone to create things like this! It actually looks extremely similar to the timer functions I made myself, but yours are actually a bit better. I even named mine add_timer() and update_timers() o.O
I've added this to the unofficial GitHub library of common functions.
@Viggles: Not sure I follow on modifying step_fn/end/fn directly. Could you provide a code example of what you mean? Anyway, I think it's ideal with more advanced cases to have the timer store a list of callbacks for step and end; that's what I do in a similar JavaScript timer implementation I use for my games, but I find it hard to imagine pico-8 games needing to become that complex.
I don't really see anything wrong with passing the timer itself to the callback, so maybe I'll do that. It'll be the last argument probably since it's the last thing anyone would likely need.
As for the time overflow thing... surely no one would play a pico-8 game for that long? If that gets to be a legitimate problem I guess it could be patched somehow.
@Scathe: thanks! you might want to mention in your github README that these functions aren't necessarily compatible with standard Lua, since at least mine use pico-8 shortcuts (e.g. +=).
@BenWiley4000: I was responding to "you can't add callbacks after the timer is initialized", and I meant doing something like this:
mytimer=add_timer(...) -- later, potentially inside the timer callback itself: mytimer.step_fn=function(...) --replacement callback here end -- timer will call the new callback from now on. |
Oh yeah, I see what you mean. You can do that for sure but it's not what I had in mind. In certain scenarios you might spawn a new object later in runtime that needs to subscribe to timer events, without disrupting existing subscriptions. I can't think of one off the top of my head, but I know I had to do something like that for a JavaScript game I wrote previously. Since pico-8's engine is so exposed, though, it's easier to get everything moving right off the bat (with one callback for each event).
@Scathe: I'd like the documentation for this API to be accessible from the github page. Maybe stick a comment at the top of the lua file with a link to this thread?
fwiw, here's a quick and unsophisticated timer function I wrote and use. Not as versatile as the one above, though.
--global vars time={ timer_set=false, timer_count=0 } function timer(start) if time.timer_set == false then time.timer_set=true time.timer_count=start end while time.timer_count > 0 do time.timer_count-=1 return false end time.timer_set=false return true end -- call with: while timer(500) == true do write("locked",56,80,8) end |
Hi all
I used a timer for rotate through titlescreen/highscore.
Here is my implementation (its someting between them above).
Initializing the timer (in my case _init() )
to check the timers in _update():
I used this solution to have the possibilities to setup serveral timers. It's not the best solution, but I hope we will get better arrays/tabels to not have to loop through all elements.
I have a pretty legit timer/tween setup here.
https://github.com/unstoppablecarl/pico-8-snippets/blob/master/src/tween.p8
Interested in hearing what you guys think.
Surprising no one is using coroutines - albeit a bit slow, this is super useful to create timers with very little actual framework code.
Example use:
-- init game futures_add(function() -- wait wait_async(30) -- trigger "exit" logic game_screen:init() cur_screen=game_screen start_screen.starting=false end) |
My framework (used in NuklearKlone, Thunderblade...):
-- update time -- draw delta time (to keep draw and update timers in sync) local time_t,time_dt=0,0 local before_update,after_draw={},{} -- futures function futures_update(futures) futures=futures or before_update for _,f in pairs(futures) do if not coresume(f) then del(futures,f) end end end function futures_add(fn,futures) return add(futures or before_update,cocreate(fn)) end function wait_async(t,fn) fn=fn or function() return true end() local i=1 while i<=t do if(not fn(i)) return i+=time_dt yield() end end -- integration in game loop function _update60() time_t+=1 time_dt+=1 futures_update(before_update) ... end function _draw() -- game drawing routine ... futures_update(after_draw) time_dt=0 end |
Hi Fred, can you create a demo of this? Something like pressing X/Z to add timers that count down/up, and then displaying the output? If this is a better solution, and particularly if it not only supports an unlimited number of down/up timers running concurrently, but also solves the integer limitation issues that cause rollover in our current timers, I'd be more than happy to merge in a pull request from you over at the Lib-Pico8 GitHub! Our little community of contributors is always looking for improvements for what we have, or additions to be added, and anyone is welcome to contribute!
[Please log in to post a comment]