Page 1 of 1

Timed callback

Posted: Fri Feb 10, 2012 8:09 am
by aidalgol
Is there a way to say "call this function after n seconds"? And if not, where in the LÖVE code should I start looking to implement this?

Re: Timed callback

Posted: Fri Feb 10, 2012 8:41 am
by kikito
I believe cron.lua is the simplest way to do it:

Code: Select all

local cron = require 'cron'

x = 0
function love.update(dt)
  cron.update(dt) -- you *must* call cron.update inside love.update()
  ...
end

...
cron.after(3, function()
  x = 1 -- set x to 1 after 3 seconds
end)
...

Re: Timed callback

Posted: Fri Feb 10, 2012 9:30 am
by miko
aidalgol wrote:Is there a way to say "call this function after n seconds"? And if not, where in the LÖVE code should I start looking to implement this?
Try this:

Code: Select all

function delay(t, fn)
  local t={fn=fn, ts=GAMETIME+t}
  table.insert(EVENTS, t)
  table.sort(EVENTS, function(a, b) return a.ts<b.ts end)
end

function updateEvents(dt)
  GAMETIME=GAMETIME+dt
  while #EVENTS>0 and EVENTS[1].ts<=GAMETIME do
    local t=table.remove(EVENTS, 1)
    t.fn()
  end
end

function love.load()
  status='waiting'
  GAMETIME=0
  EVENTS={}
  delay(5, function() status='fired 5' end)
  delay(15, function() status='fired 15' end)
  delay(10, function() status='fired 10' end)
end

function love.draw()
  love.graphics.print(status, 1, 1)
end

function love.update(dt)
  updateEvents(dt)
end

Re: Timed callback

Posted: Fri Feb 10, 2012 6:28 pm
by aidalgol
[quote="kikito"]I believe cron.lua is the simplest way to do it:

Yeah, that looks like exactly what I want. Thanks!

Re: Timed callback

Posted: Fri Feb 10, 2012 7:35 pm
by coffee
miko wrote: Try this:

Code: Select all

...
Thank you for sharing miko your minimal timer. I never had opportunity till now of use kikito's library that seems also awesome. There isn't no problems/limitations "arg" something big as call a entire function with multiple args or is advisable assign function to a var first?

Re: Timed callback

Posted: Fri Feb 10, 2012 8:07 pm
by Robin
coffee wrote:Thank you for sharing miko your minimal timer. I never had opportunity till now of use kikito's library that seems also awesome. There isn't no problems/limitations "arg" something big as call a entire function with multiple args or is advisable assign function to a var first?
Nope. Lua doesn't work the way you seem to think it works. It's like what C++ calls "by reference". The reason it looks like "by value" in some cases, is that numbers and strings are immutable in Lua.
So passing a function as argument has the same performance (both memory and time) as passing a string, a number or a table.

Re: Timed callback

Posted: Fri Feb 10, 2012 9:33 pm
by kikito
Robin wrote:
coffee wrote:Thank you for sharing miko your minimal timer. I never had opportunity till now of use kikito's library that seems also awesome. There isn't no problems/limitations "arg" something big as call a entire function with multiple args or is advisable assign function to a var first?
Nope. Lua doesn't work the way you seem to think it works. It's like what C++ calls "by reference". The reason it looks like "by value" in some cases, is that numbers and strings are immutable in Lua.
So passing a function as argument has the same performance (both memory and time) as passing a string, a number or a table.
If you are going to use the function only once or twice, as robin says, the two pieces of code below are the equivalent.

Code: Select all

-- creating the function in advance
local f = function()
  <dosomething>
end
cron.after(5, f)
-- creating the function directly in the call
cron.after(5, function() <dosomething> end)
Creating functions is not free; it has a cost. Invoking them also has a cost. But if you are going to need to invoke the same function several times, it is cheaper to create it only once, and invoke it several times, than to create and invoke it every time.

So if you are going to use the same callback several times, it's better to move it to a variable:

Code: Select all

-- this creates 1 function, and invokes it 100 times
local f = function()
  <dosomething>
end
for i=1,100 cron.after(5, f) end

-- this creates 100 equal functions, invoking each one one time
for i=1,100
  cron.after(5, function() <dosomething> end)
end
It's the same idea as with any other value, really. If you are going to need it more than once, store it in a variable so you don't have to calculate it again. But if you are using it only once, storing it in a variable might just make the code longer and clumsier.

It's also worth nothing that in some occasions functions look the same, but they are not - they might be different closures each time; the variables they access/modify are named the same, but are different values in memory.

Finally, just reminding that if you want to repeat something periodically, you can use cron.every . No need to "craft" your own periodical function using cron.after (although it is an interesting exercise).

Re: Timed callback

Posted: Fri Feb 10, 2012 10:05 pm
by coffee
kikito, robin, thank you both both for enlarging my horizon and the advices about this question. I started to had more idea of doing separated tables with timers for each "activity" (one for animations, other for messages etc) but probably I will revise my objective and do a general one calling functions to deal with all time work. Following your advices I will try avoid making mistakes. kikito, I will end probably using cron for others later projects but for now and for learning it's really important to learn and know how to code with time.