When developing applications, it’s important to handle scenarios that occur as a result of the user interacting with your game in as many different ways possible. It’s equally as important to handle scenarios that occur as a result of “system” events, whether they are explicitly triggered by the user or not.

Things that immediately come to mind are things that cause your app to become “suspended” such as the user receiving a phone call, or pressing the “home” button on their device (your app is still running in the background, but in a suspended/paused state). What about when the user comes back to your app while it is suspended, or when your app exits completely?

All of those things are handled by “system” events in Corona, and that’s what I’ll be going over today.

Event Listener

Before you can start monitoring system events in your Corona app, you need to set up a listener function, and add a “system” event listener. If you’re not familiar with events in Corona, I suggest you read The Corona Event Model Explained document before continuing.

The code below—commonly placed at the end of main.lua—shows how to setup your event listener, and also add it to the global Runtime object (the only object that can listen for “system” events).


local function onSystemEvent( event )

– Test for different event types here

end
Runtime:addEventListener( “system”, onSystemEvent )

applicationStart


local function onSystemEvent( event )
if event.type == "applicationStart" then

do_something()

end
end

The above code example shows how to test for the “applicationStart” event type in your system event listener.

You app will receive an “applicationStart” event when your app launches (from a closed/cold state, not a suspended state), and after the code in main.lua has executed.

applicationExit


local function onSystemEvent( event )
if event.type == "applicationExit" then

do_something()

end
end

The “applicationExit” system event is dispatched just prior to your app quitting (e.g. not suspending, but fully closing). This can occur from the user explicitly, or if the operating system’s task manager tells the app to close for whatever reason (usually due to your app being the least recently used, in low memory situation).

Things that this event is most commonly used for is to do any last-minute data saving, closing open database connections, etc.

Update: there are many circumstances in which the “applicationExit” system event wont be dispatched so don’t rely on it for important application logic. For example, if the user force-closes the application or the battery is removed from the device without properly shutting it down. Applications on mobile devices generally have to assume that they may just stop at any point and will be restarted from scratch.

applicationSuspend


local function onSystemEvent( event )
if event.type == "applicationSuspend" then

do_something()

end
end

I touched on this briefly already, but if the user receives a phone call, or anything happens that causes the user to have to switch out of your app on their device, or if the user presses the “power” button and puts their device to sleep, your app will go into a suspended state (but will not quit).

Prior to going into this suspended state, an “applicationSuspend” event will be dispatched, which gives you a chance to do things such as pause the game (so the user will be at the pause screen when they come back, instead of on the verge of being defeated!), mark the time (for any time-tracking functionality), pause/stop any timers and/or transitions, etc.

applicationResume


local function onSystemEvent( event )
if event.type == "applicationResume" then

do_something()

end
end

Speaking of your app being suspended, you also have a chance to “do something” whenever your app comes back from the suspended state, which is where the “applicationResume” event comes in.

Putting it all together


local function onSystemEvent( event )
if event.type == "applicationStart" then

– this block executed when application launches (after main.lua)

elseif event.type == “applicationExit” then

– this block executed just prior to the app quitting
— OS closes least recently used app, user explicitly quits, etc.

elseif event.type == “applicationSuspend” then

– this block executed when app goes into “suspend” state
— e.g. user receives phone call, presses home button, etc.

elseif event.type == “applicationResume” then

– this block executed when app resumes from “suspend” state
— e.g. user goes back into app (while it is still running in bg)

end
end
Runtime:addEventListener( “system”, onSystemEvent )

The above is a barebones system event listener, which you can actually use as a template. Of course, what you put into the individual if/else blocks is completely up to your app.

If you pay close attention, you’ll notice almost every commercial-grade application or game makes use of one or more of the system events mentioned in this tutorial—and for good reason: they are not only absolutely necessary for some apps, but they can be leveraged to enhance the user experience tremendously for many apps.

Before releasing your app, take a moment and think to yourself, What should my app do when it goes into suspended mode? When it comes back? Before it closes? And you’ll likely find a way to make your app even better, or perhaps solve a problem you didn’t know the solution to prior to learning about system events.

  1. PERFECT! Exactly what I needed. Two questions if i may:

    1- If understand correctly, I need to put the code above only at the bottom of main.lua and nowhere else. Correct? (i am using Director and have multiple modules)

    2- In my gameScreen.lua module (where the game play is) I have a PAUSE button and an attached listener function. This function pause the physics, sound..How do I pause the game say when the player press the home button? The pause function is not in scope in the main.lua module. Do i need to make my pause function in gameScreen.lua global?

    I hope I making sense but in event, thank you so much Jon for making hard stuff easier to understand every week. Love it!

    Mo
    (LairdGames)

  2. Can you give a meaningful example for applicationStart, i.e. how is this different from just starting the app?

  3. @Mo

    1 – Yes, but all your function calls have to go there too.
    2 – Yes, the easiest solution is to make it global.

  4. Hey thanks Max! Not sure i understand you correctly.

    1- What do you mean by “all your function calls have to go there too”?

    2- I thought “global” was a bad word!?

    Thanks again.

    Mo

  5. Maybe a small example with 2 modules using Storyboard would help. I am using director but I am sure I can figure out what to do even with a storyboard example. Thank you!

    Mo

  6. @Mo

    I had that question as well. There was a similar tutorial awhile back on mobile tuts. The author of that article suggested removing the runtime event listener for system event functions when cleaning up a scene. To me, that sounded like the system event function (example above) would go in each module.

  7. @Perry

    That will make sense to me too because it would avoid having to deal global functions and simplify the code since you will deal with game pause for instance in the module where the game is actually running.

    Maybe Jon can show us an implementation example…

    Thanks Perry.

    Mo

  8. @Mo

    Thanks for the link, very helpful, but the thread dies out just as it was getting good :(

    I’m not sure how that would affect things. You would remove the listener in the module on exit but it seems like the runtime listener in main.lua would always be running (good or bad?).

    Perry

  9. Jonathan Beebe says:

    The easiest option would be to add the system event listener in main.lua, and have your pause function global.

    Remember, it’s not “evil” to have global functions, you just have to weight out in your mind when it is best to avoid them, and best to use them. Everything in Lua is a table lookup (no matter whether it is local or global), it’s just that global look-ups generally take longer because they cover a wider scope.

    However, to ease your mind, here’s what you can do. Assuming your actual game is in the “enterScene” listener function of your “game” scene. At the top of the “enterScene” event, you could do this:


    local pause = pauseFunction

    “pauseFunction” in the example above would be the ‘global’ pause function that needs to be accessed several places. Now whenever you call pause() from within that block, you’ll still be calling the original function, but this time the look-up is using the local reference within the block instead of having to find the function in the global space.

    Of course, that’s an example—your actual game code that needs the function might be in a different function (not within the enterScene listener). But the point is, you can localize a global function within the block that it’s needed, and whenever you call the local reference, the look-up is local rather than global—if you’re dealing with a function that needs to be executed as fast as possible (I could see why ‘pause’ might fit into that category).

  10. Hello Jon.

    THANK YOU! I am afraid i am still confused.OK here a really concrete example:

    What if I have this on my game.lua sceen (which pause the game if the btPause button is pressed):

    ————————————————————-

    local function pauseGame()

    if fxOn then audio.play( tapSound ) end

    isGameActive = false
    btPause.isVisible = false
    btExit.isVisible = true
    btResume.isVisible = true
    physics.pause()
    Particles.Freeze()
    audio.pause(gameMusic)
    timer.pause(rockTimer)

    end

    end

    local function btPauseTouch (event) —- listener for a pause button in gameScreen.lua

    local phase = event.phase

    if phase == “release” then

    pauseGame()

    end

    return true

    end
    —————————————–

    Would I need to simply make pauseGame() a global function (remove the LOCAL in front of it in gameScreen.lua)? And then simply call that function from main.lua like this:

    local function onSystemEvent( event )
    if event.type == “applicationResume” then

    pauseGame()

    end
    end

    Sorry for being “dense” today:(

    Mo

    ps: By the way, thanks to you and some others in the forum, I am starting to get comfortable with globals. They no longer scare me late at night:)

  11. Jonathan Beebe says:

    @Mo: If you remove “local” from your pauseGame() function definition, then it will be global. The problem I foresee you running into is if the app gets an “applicationSuspend” event before your pauseGame() function is defined (e.g. the user gets a phone call on the main menu, before they even get to game.lua).

    What you can do is check if it exists before attempting to call it. So in your system event listener, it would look something like this:


    local function onSystemEvent( event )
    if event.type == "applicationSuspend" then
    if _G.pauseGame then
    _G.pauseGame()
    end
    end
    end
    Runtime:addEventListener( "system", onSystemEvent )

    Also, I normally prefix globals with _G. for two reasons: 1) so when I’m looking back at my code I can clearly see what is global and what is not and 2) it prevents you from accidentally overriding a local variable within scope that uses the same name (and other odd situations like that).

    So in other words, I would just use _G.pauseGame when defining the function, and also when calling it. _G. is a reference to the “global” Lua table that the entire Lua environment resides in.

  12. @Jon: PERFECT! One more question if I may (I think Perry had the same one)

    Would you put your code:

    local function onSystemEvent( event )

    end

    ONLY at the bottom of main.lua and no other place (no other modules)?

    Thanks again for your patience with me today. And please keep these wonderful blog posts coming!

    Mo

  13. IMHO it depends. I have some code that I want to be run only while ceratin window is shown. Instead of checking active window etc. I just add event listener on creation of this window and remove it after it is done showing – everything handled in one module.

  14. I have a problem that may or may not be possible to solve…

    My game is a puzzle game in which the player should not be able to see the game scene when the game is paused, otherwise they will be able to cheat the clock.

    So when the player suspends the app I want to goto a pause scene. I have all the data save and game resume functionality in place but the problem is that by calling storyboard.gotoScene from within my onSystemEvent function, I can only manage to get the app to switch scenes after the resume. This is regardless of whether I call it on the condition if type == “applicationSuspend” or if type == “applicationResume”.

    So the problem is that when the user double presses the home button to switch between apps on iOS 7, they can see a small preview of the game, which shows them the gameScene.

    Is it possible to switch scenes before the app goes into suspend mode or if not is it possible to control what is shown in the app preview?

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title="" rel=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>