Time Delays
timer.performWithDelay() is Corona’s function for performing specific actions after a set period of time. The function name is actually very descriptive, so it’s likely you already knew what it did as soon as you saw it.
Here’s an overview of the syntax:
timer.performWithDelay( delay, listener [, iterations] )
When you call the function, you specify how long you want the delay to last in milliseconds (delay), and then you specify the function (listener) you want to be called once the delay time has lapsed. Optionally, you can specify the number of iterations you want the delay to be repeated (the default is 1 iteration).
What are iterations?
The timer iterations are how many times the delay sequence will loop over and over again. Basically, you’re telling the app to: “wait X milliseconds then call Y function, wait X milliseconds then call Y function…” and so on for the number of iterations you specified (or infinitely if set to 0).
Next I’ll show you how you can use both functions and anonymous functions as listeners when using timer.performWithDelay().
Using a function
In the example below, we are calling a function called hello_world() after 1 second (1000 milliseconds) only one time (1 iteration):
local function hello_world()
print( "Hello world!" )
end
timer.performWithDelay( 1000, hello_world, 1 )
hello_world vs. hello_world()
Before I continue, I need to clarify a HUGE point of confusion for many developers. Notice how I used hello_world instead of hello_world() as the second argument to timer.performWithDelay() in the above example?
This is because it is only asking for a reference to an existing function, and therefore we just need to use the variable name of the function. If I were to use hello_world() (with parenthesis), I’d be actually calling the function and the second argument would instead be whatever is returned from hello_world()—which is nil because by default functions return nil when there is no return statement.
Using anonymous functions
Since the second argument of timer.performWithDelay() simply has to be of type “function”, you can also use an anonymous function (one without a name; not assigned to a variable). The below example does exactly the same thing as the previous example:
timer.performWithDelay( 1000, function()
print( "Hello world!" )
end, 1 )
Of course, I could have put everything on one line, but I decided to make it “look” like a function definition for easier readability.
Also keep in mind that with anonymous functions, we’re actually defining the whole function (from “function()” … all the way to … “end”) entirely between the commas that separate the function arguments. Therefore, timer.performWithDelay() actually takes it as a valid argument (we’re not calling a function, we’re defining it—which serves the same purpose as a reference to a function).
You can get more information on using closures as function callbacks in Eric Wing’s tutorial that he published over a year ago.
Passing Arguments to the Listener
One of the most common questions in regards to using timer.performWithDelay() is, “Since I’m passing only a reference to an external function, what if that function takes arguments?”
The answer is, use a combination of the two examples from above. That is, use an anonymous function and an external function:
local function hello_world( arg1, arg2 )
print( "Hello world!", arg1, arg2 )
end
timer.performWithDelay( 1000, function()
hello_world( "first", "second" )
end, 1 )
Do you see how I did that? Since hello_world, our listener function, takes two arguments (arg1 and arg2), we use an anonymous function as the listener which in-turn calls the hello_world() function with the arguments we need to pass in (“first” and “second”).
It might take a while to soak in, but once you work with timer.performWithDelay() enough, things begin to make sense pretty quickly. In fact, using this function regularly and taking the time to fully understand how it works can actually work wonders in helping you understand some of Lua’s extremely important but somewhat confusing features.
Other functions
It’s worth noting that timer.performWithDelay() actually returns a timerId that can be stored into a variable and used with other functions in Corona’s timer library. These functions include timer.pause(), timer.cancel(), and timer.resume() which are beyond the scope of this tutorial. Thankfully, they are fairly self-explanatory once you’ve mastered the use of timer.performWithDelay(). Visit the timer API reference page for more information.
Counting Time
As I mentioned earlier, there are countless reasons why you might want to keep track of time in your app. For the sake of this tutorial, let’s assume you want to begin counting time at the start of a round and stop once the player has reached a “game over” state.
So, at the start of the round:
local markTime = os.time()
os.time()
This function returns the current time (when called without arguments, as shown above), but it can do more than that. More information here.
Once the player has reached the “game over” state (at the end of the round), here’s how we would get the total amount of time passed since we first marked the time and stored it in markTime:
local timePassed = os.time() - markTime
In the above example, timePassed actually gives you the time in seconds. You can convert the time into minutes by dividing the value by 60, or multiply it by 1000 to get milliseconds. A faster way to get milliseconds right off the bat is to substitute os.time() with system.getTimer() in both code snippets above.
Time’s up!
So by now, you should be a pro at using Corona’s timer.performWithDelay() function, and also have a good understanding of how you can track/count time in your app. All in all, that should cover most use-cases having to do with time.
But in case you want to get daring, some other time-related functions you may want to check out include: os.clock(), os.date(), os.difftime(), and system.getTimer().




Naomi
Thank you for posting the tutorial. Regarding the iteration, I believe the default is 1 (not 0) — maybe a typo? Or do we need to add 1 now if we don’t want it to iterate infinitely…?
John
Good article. However, I’m a bit worried about your use of “closure” in this context. I would prefer the phrase “anonymous function” here since this example is not capturing local variables which is the essence of closure.
see http://en.wikipedia.org/wiki/Closure_%28computer_science%29
Jonathan Beebe
Oops, nice catch! I updated the article to be accurate (1 as the default).
And I also updated the article to use the phrase “anonymous function” instead of closure to prevent any confusion
Thanks for the feedback!
Mo
Good timing Jon! I am working on collision and timer and this was perfect!
Mo
(LairdGames)
Mark
Note that calculating elapsed time is more complex if you have to take account of pausing gameplay or the OS switching to another app!
Chris
Very timely article (sorry for the pun). Cleared up a few problems I was having with regards passing parameters to functions from a timer.
Many thanks
Nick
This article came just in time. It was very timely and also save me some time. I also had a good time, while reading about it…this time. Maybe next time I’ll have a better time, but right now it’s the best time and the right time to read about time.
Good times.
That’s right, I went there. Great article,
I really enjoyed the
local function hello_world( arg1, arg2 )
print( "Hello world!", arg1, arg2 )
end
timer.performWithDelay( 1000, function()
hello_world( "first", "second" )
end, 1 )
I’m not cool enough yet to realize you could do that! I already have many uses for that
Thanks again!
ng
Mo
Hello Jonathan.
Sorry to steal some space from this thread but is there ANY chance to see a tutorial on in-app purchase (ios)? I have been reading about it all over the forum but only you can make something complex easy to understand. Obviously this “working with time” is a good example among others!
Please, please, pretty please:)
THANKS!
Mo.
(LairdGames)
Tadd
I used a lot of this type of call in my game previously, but it ended up being so many it really bogged down the game and I couldn’t get them to cancel right. So I ended up making a variable to count for me …
LIke …
local timervar = 0
function timevarincrease()
timevar = timevar + 1
// if something happens at a certain ‘time’
if timevar >= 50
timevar =0
end
end
Runtime:addEventListener(“enterFrame”, timevarincrease)
This worked better. I’m sure I did 1000 things wrong with dropping the time function but .. time will tel. HAH!