We are excited to introduce the Composer API, our new scene manager!
It is available immediately in open beta.

For those of you new to scene management, it allows you to create Lua files that represent a scene in your app. When you navigate to different scenes using API calls, Composer handles the transitions and helps you easily clean up. It’s a very useful tool and can make creating and managing your games and apps much easier.

What about Storyboard? There are actually lots of similarities with Storyboard, but we decided to do something new because we wanted to provide a simpler event model and a more scaleable structure for scene lifecycle management. Not only is Composer easier to use, but it will also allow us to build better and more interesting things in the future.

Please note: Although we will no longer support Storyboard, you can keep on using it. It is going to be included in Corona SDK for 9 more months and it is available as open source code, so you will be able to keep on using it for as long as you like. Of course, we recommend moving to the Composer API for all new apps and eventually migrating existing apps.

Now on to the Composer API!


If you want to jump right in, please start with the Composer Migration Guide.

In the meantime, here’s a summary of what you need to know:

Scene Events

In Composer, the scene events have been renamed to better reflect what they do. Instead of the myriad of events in Storyboard, Composer has just four key events: create, show, hide, and destroy.

Storyboard → Composer

scene:createScene() → scene:create()

scene:willEnterScene() + scene:enterScene() → scene:show()

scene:exitScene() + scene:didExitScene() → scene:hide()

scene:destroyScene() → scene:destroy()

scene:overlayBegan()(removed)

scene:overlayEnded()(removed)

Notice that the separate overlay events have been removed. Composer still supports overlays, but we’ll cover that topic in a bit. One of the primary design goals for Composer was to reduce the eight separate events into a more manageable set without losing the ability to detect multiple events. In addition, we’ve renamed several function names and scene events to make them more logical.

Why a New Library?

While Composer is very similar to Storyboard, we realized that we needed to refactor the library into a more sustainable codebase that is cleaner and more scalable for the future. We listened to your feedback about the complexity of the event system and we’ve worked to simplify that while retaining the core functionality you asked for. The changes in function and event names should also be easier to understand.

Diving Into the Scene Template

You should use the following scenetemplate.lua file to construct your scenes from. This basic template has the core features needed to implement a Composer scene:

The top portion of the scene isn’t much different than Storyboard: load the Composer library and then create this scene’s scene object using composer.newScene(). Next, you should include any scene-wide functions and forward-declare local variables that will be used in the scene. Because Lua files are only loaded once, variables that you set here will not be reset when you revisit the scene unless you take explicit steps to unload the file.

After that reside the four functions to handle events generated for the scene:

scene:create()

This function is primarily used to create the display objects for a scene — basically, anything to display in the scene (but not native objects; we’ll talk more about them in a bit). This is also a good point to load, but not play, scene-specific audio files.

For Composer to “manage” your scene and the display objects within, all of these objects must be inserted into the scene’s view display group or a child display group of it. This group is referenced by the critical line at the top of each listener function:

All display objects for the scene should be inserted into this group, for example:

For developers coming from Storyboard, recall that some versions of the template called this display group group or screenGroup. To make it more clear in Composer, we’ve renamed it to sceneGroup.

Note that the scene:create() function is only called if the scene’s view does not exist — that is, it will be called the first time the scene is loaded. However, Composer tries to keep the scene in memory assuming that you’ll revisit it later, so if the scene remains in memory, scene:create() will not be called.

scene:show()

In Composer, scene:show() replaces both the willEnterScene() and enterScene() functions from Storyboard. This function will be called twice when a scene shows: once for each of these phases:

  • “will” — called when the scene is still off screen (but is about to come on screen).
  • “did” — called when the scene is fully on screen.

These new string values are specified in the event.phase table entry. The “will” phase is a great opportunity to reposition objects that may have moved from their intended starting position since the scene was last shown (like restarting a game level).

The remainder of the action will happen in the “did” phase of scene:show() — this is the proper place to create native objects like text fields, maps, etc. Why? Since native objects cannot be inserted into display groups, and thus not into the scene’s view group that is managed by Composer, you must create them after the scene is fully on screen.

The “did” phase is also a good opportunity to start transitions/timers, play scene-specific music, and start the physics simulation if you’re using Corona’s physics engine.

scene:hide()

In Composer, scene:hide() replaces both the exitScene() and didExitScene() functions from Storyboard. This function will be called twice when a scene is hidden: once for each of these phases:

  • “will” — called when the scene is on screen (but is about to go off screen).
  • “did” — called immediately after scene goes off screen.

Note that the scene:show() and scene:hide() events are tied together — for each show event, there’s a corresponding hide event. Therefore, during the will phase of scene:hide(), you may need to:

  • pause or stop physics
  • cancel timers and transitions
  • remove native objects
  • stop scene-specific audio

Generally, there isn’t much to handle in the “did” phase of scene:hide(), although you could remove the scene’s view group or even remove the scene permanently if you desire.

scene:destroy()

The scene:destroy() function is where Composer cleans up the scene’s display objects (any non-native display object that you inserted into the scene’s view group or a child group of it). scene:destroy() is called just prior to this clean up. Here you can “undo” things that you did in scene:create() which are not related to the scene’s display objects, for example, dispose of scene-specific audio.

Because Composer tries to keep scenes in memory for performance reasons, this function is only called in these circumstances:

  1. If an explicit call is made to composer.removeScene().
  2. If Composer is set to automatically remove the scene’s view.
  3. If the app receives a low memory warning from the OS.

If you loaded audio files into memory inside the scene:create() function, scene:destroy() is a good time to dispose of the audio. Similarly, if you opened access to a database in scene:create(), you may close it here.

Removing/Recycling Scenes

In Storyboard, there was a concept of purging and removing scenes, but the terminology was confusing. Although it seemed like an extreme operation, purging was merely the act of removing the scene’s view, but the actual Lua file remained in memory. By comparison, removing a scene both purged the scene and removed its scene object from memory.

In Composer, there is just one function for this: composer.removeScene(). It accepts a parameter (shouldRecycle) which controls how “deep” the operation goes:

  • composer.removeScene( “myScene”, true ) — this acts like the purge event, which is now referred to as recycling. In this case, only the scene’s view is destroyed. Consider this as if you placed a file in the trash/recycle bin of your OS… it’s out of sight, but the file still exists. If/when you come back to the scene, its scene:create() event will execute again, but any code outside of the listener functions will not be re-executed since the scene object resides in Lua’s memory.
  • composer.removeScene( “myScene”, false ) or composer.removeScene( “myScene” ) — calling this function with false or nil will destroy the scene’s view and unload the scene from Lua’s memory. Consider this as if you placed a file in the trash/recycle bin of your OS and then emptied the trash/bin… the scene is effectively removed and must be re-created if/when returning to it.

Going to Scenes

Once you create scene files, you need a method to access them. In Composer, this is accomplished via composer.gotoScene(). It requires a sceneName parameter which corresponds to the name of the Lua file. For example, if you have a scene file named gamecredits.lua, access that scene with:

Notice that sceneName is simply the name of the scene file without the .lua extension. In addition, an optional table of parameters controls how the scene transitions on screen:

This tells the scene to transition in with a “fade” effect over the span of 500 milliseconds. For a list of valid transitions, see the composer.gotoScene() documentation.

If you want to pass data to a scene, composer.gotoScene() allows this as well — simply include a table of data named params in the options table…

…and then access this data from the event.params table in the target scene’s scene:create() or scene:show() function:

Overlays

Like Storyboard, Composer allows you to have one overlay scene. This is a scene that gets loaded on top of the active scene (the parent scene). An overlay scene is constructed like any other Composer scene and it receives the same core events as any other scene.

Because an overlay scene may not cover the entire screen, users may potentially interact with the parent scene underneath. To prevent this, set the isModal parameter to true in the options table of composer.gotoScene(). This prevents touch/tap events from passing through the overlay scene to the parent scene.

To dismiss (hide) the overlay, call composer.hideOverlay(). For example:

As mentioned earlier, the events for overlayBegan and overlayEnded have been removed. Instead, the overlay scene now has access to the parent’s scene object via event.parent. This allows you to access functions/methods in the parent scene and communicate with the parent when the overlay scene is shown or hidden. For example:

Final Notes

The Composer API is our new scene manager because it is built upon a more stable, future-proof base and it offers a simplified collection of functions and events. This allows us to expand and improve the library moving forward, providing Corona developers with a solid solution for scene management.

Read the article:

Introducing the Composer API (plus tutorial!)