Storyboard API examples?

Hi All,

It seems that not only is the Storyboard API an effective way to manage screen transitions but that it is also pretty central to the game/app templates that shipped with the recent versions of Corona SDK.

I’m a fairly novice programmer and want to make sure I really get my head around working within the context of the Storyboard API.

Can anyone point me to any shared code that demonstrates how to program in the context of the Storyboard API? I feel like I understand how to work with the API in theory but in practice I keep experiencing problems.

I’m working on two things:

  1. I want to modify the Storyboard Sample Code that’s referenced in the API directory (https://github.com/ansca/Storyboard-Sample) to use buttons instead of taping the background. My goal is to have the capability to build a simple “Choose Your Own Adventure” style short story.
  2. I’m trying to bring a menu system to the “Orb Smasher” tutorial game (http://www.youtube.com/watch?v=6TsDdLY7VXk) as preparation for working on a more developed game idea later down the road.

Thanks in advance for any examples, tips or pointers :slight_smile:
[import]uid: 105707 topic_id: 19685 reply_id: 319685[/import]

Here is my code. I followed Jon Beebe’s. It works which is good, however I am novice so my technique
is far from perfect. for example i cannot seem to remove the ‘dropButton’ eventListener. Can someone
help me with that? also I’m not sure whether to remove my event listeners in ‘exitScene’ or ‘destroyScene’.
I did in exitScene. You can copy and paste in 3 files (main.lua, scene1.lua(line 19), scene2.lua(216)
it will take you to level2. Simply move the white box then tap the white box that appears to drop.

Also at this point i’m still learning memory management and leakage.

I believe i got the ‘purgeScene’ correct on line 285 of scene2.
[lua]–main
local storyboard = require ‘storyboard’

storyboard.gotoScene(‘scene1’)
–[[
local function garbagePrinting()
collectgarbage(“collect”)
local memUsage_str = string.format( “memUsage = %.3f KB”, collectgarbage( “count” ) )
print( memUsage_str )
local texMemUsage_str = system.getInfo( “textureMemoryUsed” )
texMemUsage_str = texMemUsage_str/1000
texMemUsage_str = string.format( “texMemUsage = %.3f MB”, texMemUsage_str )
print( texMemUsage_str )
end

Runtime:addEventListener( “enterFrame”, garbagePrinting )
–]]

–scene1–


– scenetemplate.lua


local storyboard = require( “storyboard” )
local scene = storyboard.newScene()

physics = require(‘physics’)
physics.start()
physics.setGravity(0,9.3)
–physics.setDrawMode(‘hybrid’)

local p = 0
local bg1, floor1, present1, dropButton

local phys1 = {friction = .7, bounce = .1, density = .3}
local h = display.contentHeight
local w = display.contentWidth
local level1Presents
local onTouch = {}


– NOTE:

– Code outside of listener functions (below) will only be executed once,
– unless storyboard.removeScene() is called.



– BEGINNING OF YOUR IMPLEMENTATION

– Called when the scene’s view does not exist:
function scene:createScene( event )
local group = self.view

bg1 = display.newRect(0, 0, w, h)
bg1:setFillColor(200,0,0)
group:insert(bg1)

floor1 = display.newRect(0, h-1, w, 1)
floor1.name = ‘floor1’
physics.addBody(floor1, “static”,{density = 9, friction = .7, bounce = .2})
–floor1:addEventListener(‘collision’, onCollision)
group:insert(floor1)


– CREATE display objects and add them to ‘group’ here.
– Example use-case: Restore ‘group’ from previously saved state.


end

– Called immediately after scene has moved onscreen:
function scene:enterScene( event )
local group = self.view
print( “1: enterScene event” )

local function level1Presents()
p = p+1
print §
if (p ==1) then
present1 = display.newRect(0,0, 50, 50)
physics.addBody(present1, ‘kinematic’, phys1)
present1.x = w/2
present1.y = h/7
present1:addEventListener(‘touch’, onTouch)
group:insert(present1)
elseif (p == 2) then

storyboard.gotoScene(‘scene2’)
end

end

function onTouch(event)

t = event.target
t.name = ‘t’
local phase = event.phase

if event.phase == “began” then
display.getCurrentStage():setFocus(t)
t.isFocus = true
t.x0= event.x - t.x

elseif t.isFocus then
if event.phase == “moved” then
t.x = event.x - t.x0
elseif event.phase == ‘ended’ or ‘cancelled’ then
display.getCurrentStage():setFocus(nil)
t.isFocus = false
createDropButton()
t:removeEventListener(‘touch’, onTouch)
end
end
return true
end

function createDropButton()
dropButton = display.newRect(w-100,h/4, 80, 80)
dropButton:addEventListener(‘tap’, dropPresent)
end

function dropPresent()
t.bodyType = ‘dynamic’
timer.performWithDelay(1000, level1Presents, 1)
display.remove(dropButton)
–dropButton:removeEventListener
end

– INSERT code here (e.g. start timers, load audio, start listeners, etc.)


level1Presents()
end

– Called when scene is about to move offscreen:
function scene:exitScene( event )

print( “1: exitScene event” )
–local group = self.view
present1:removeEventListener(‘touch’, onTouch)

–dropButton:removeEventListener(‘tap’, dropPresent)

– INSERT code here (e.g. stop timers, remove listeners, unload sounds, etc.)


end

– Called prior to the removal of scene’s “view” (display group)
function scene:destroyScene( event )
–local group = self.view
print( “((destroying scene 1’s view))” )


– INSERT code here (e.g. remove listeners, widgets, save state, etc.)


end


– END OF YOUR IMPLEMENTATION

– “createScene” event is dispatched if scene’s view does not exist
scene:addEventListener( “createScene”, scene )

– “enterScene” event is dispatched whenever scene transition has finished
scene:addEventListener( “enterScene”, scene )

– “exitScene” event is dispatched before next scene’s transition begins
scene:addEventListener( “exitScene”, scene )

– “destroyScene” event is dispatched before view is unloaded, which can be
– automatically unloaded in low memory situations, or explicitly via a call to
– storyboard.purgeScene() or storyboard.removeScene().
scene:addEventListener( “destroyScene”, scene )


return scene

–this is scene2



– scenetemplate.lua


local storyboard = require( “storyboard” )
local scene = storyboard.newScene()

physics = require(‘physics’)
physics.start()
physics.setGravity(0,9.3)
–physics.setDrawMode(‘hybrid’)

local p = 0
local bg1, floor1, present1, dropButton

local phys1 = {friction = .7, bounce = .1, density = .3}
local h = display.contentHeight
local w = display.contentWidth
local level1Presents
local onTouch = {}


– NOTE:

– Code outside of listener functions (below) will only be executed once,
– unless storyboard.removeScene() is called.



– BEGINNING OF YOUR IMPLEMENTATION

– Called when the scene’s view does not exist:
function scene:createScene( event )
local group = self.view

bg1 = display.newRect(0, 0, w, h)
bg1:setFillColor(0,0,200)
group:insert(bg1)

floor1 = display.newRect(0, h-1, w, 1)
floor1.name = ‘floor1’
physics.addBody(floor1, “static”,{density = 9, friction = .7, bounce = .2})
–floor1:addEventListener(‘collision’, onCollision)
group:insert(floor1)



end

– Called immediately after scene has moved onscreen:
function scene:enterScene( event )
local group = self.view
storyboard.purgeScene( “scene1” )
print( “1: enterScene event” )

local function level1Presents()
p = p+1
print §
if (p ==1) then
present1 = display.newRect(0,0, 50, 50)
physics.addBody(present1, ‘kinematic’, phys1)
present1.x = w/2
present1.y = h/7
present1:addEventListener(‘touch’, onTouch)
group:insert(present1)

end

end

function onTouch(event)

t = event.target
t.name = ‘t’
local phase = event.phase

if event.phase == “began” then
display.getCurrentStage():setFocus(t)
t.isFocus = true
t.x0= event.x - t.x

elseif t.isFocus then
if event.phase == “moved” then
t.x = event.x - t.x0
elseif event.phase == ‘ended’ or ‘cancelled’ then
display.getCurrentStage():setFocus(nil)
t.isFocus = false
createDropButton()
t:removeEventListener(‘touch’, onTouch)
end
end
return true
end

function createDropButton()
dropButton = display.newRect(w-100,h/4, 80, 80)
dropButton:addEventListener(‘tap’, dropPresent)
end

function dropPresent()
t.bodyType = ‘dynamic’
timer.performWithDelay(1000, level1Presents, 1)
display.remove(dropButton)
–dropButton:removeEventListener
end

– INSERT code here (e.g. start timers, load audio, start listeners, etc.)


level1Presents()
end

– Called when scene is about to move offscreen:
function scene:exitScene( event )

print( “1: exitScene event” )
–local group = self.view
present1:removeEventListener(‘touch’, onTouch)

–dropButton:removeEventListener(‘tap’, dropPresent)

– INSERT code here (e.g. stop timers, remove listeners, unload sounds, etc.)


end

– Called prior to the removal of scene’s “view” (display group)
function scene:destroyScene( event )
–local group = self.view
print( “((destroying scene 1’s view))” )


– INSERT code here (e.g. remove listeners, widgets, save state, etc.)


end


– END OF YOUR IMPLEMENTATION

– “createScene” event is dispatched if scene’s view does not exist
scene:addEventListener( “createScene”, scene )

– “enterScene” event is dispatched whenever scene transition has finished
scene:addEventListener( “enterScene”, scene )

– “exitScene” event is dispatched before next scene’s transition begins
scene:addEventListener( “exitScene”, scene )

– “destroyScene” event is dispatched before view is unloaded, which can be
– automatically unloaded in low memory situations, or explicitly via a call to
– storyboard.purgeScene() or storyboard.removeScene().
scene:addEventListener( “destroyScene”, scene )


return scene – CREATE display objects and add them to ‘group’ here.
– Example use-case: Restore ‘group’ from previously saved state.

[import]uid: 75779 topic_id: 19685 reply_id: 76342[/import]

Hi rmckee,

I appreciate the insight you’ve shared. By looking at your code I realized that I had not been adding my buttons to the group Group so that when group was removed (apparently automatically by the storyboard API?) the buttons would be left in the display. I’ve added the following and solved that problem:

group:insert(button1)  

The concept of Groups seems pretty basic to the Corona experience so I’m glad I’ve started to understand this!
I too am trying to better understand garbage collection in the context of the Storyboard API. I’d love to hear if anyone has insight regarding your exitScene and destroyScene questions!

It feels like createScene, enterScene and exitScene all fire automatically but I’m not clear on if/when destoryScene goes. [import]uid: 105707 topic_id: 19685 reply_id: 78851[/import]

destoryScene is closely associated with garbage collection. You mentioned wanting to know more about garbage collection so I’ll try to explain both. Most modern languages today have something known as garbage collection which older languages did not. In older languages you had to manually keep track of all of your variables and systematically clear them from memory. If you didn’t then you would eventually run out of available memory because all of it would be filled by storing variables that you were not longer using. You don’t want to dispose of your unused variables every time you finish with one because it takes processing power. If you did your application could be viewed as having performance issues. This is where garbage collection comes in. In Corona when we finish with a variable we set its value to nil. This is an indicator to the SDK that we are finished with that variable and no longer want it in memory. When we do that it is not instantly removed from memory. The SDK monitors the available memory and when more memory is needed then it calls for garbage collection to be run. At this point it scans for all of the variables in memory with a value of nil and removes them to make room for other variable data. Garbage collection (or GC) is something that is preformed for you via the SDK and not something that you need to think about in general. Once you set your value to nil your done and can leave the rest to the SDK and GC. If you find a spot in your application that you are finding memory issues you can manually call garbage collection when needed.

That brings us to destroyScene. createScene, enterScene and exitScene all happen at known predictable times that correspond with switching to a new scene or leaving a scene. destroyScene is not as predictable. destroyScene is run right before a display group (or scene) is removed. What this means is that when garbage collection is about to run the SDK will look at the destroyScene methods that have not been run for the scenes that have been exited and will run the code in those methods. This could include closing connections to files, databases, making sure that you have set certain variables and groups to nil, etc. Anything that needs to be finalized before the scene group is completely destroyed and removed from memory. Once the destroyScene method had been run then GC is run to clear out the available variables and completely remove the scene from memory.

Hope that helps!

Jason Presley
Twitter: @MeOnCoronaSDK
Blog: jasonpresleyjer2911.tumblr.com [import]uid: 136162 topic_id: 19685 reply_id: 96667[/import]

Wow… I feel like I have a much better ability to visualize how this is meant to work. I appreciate your effort to explain this.

To further your discussion of GC, am I right in saying that in Java, GC is handled “behind the scenes” but in C++ you need to actively manage it?

If I were building an RPG style of game in Corona where a player often entered and left certain scenes, would a good process be to use the exitscene function to save important state variables that you could reference for the createscene function on one’s next “visit”? Would I use the destroyscene function to destroy variables/values that were not important to remember and let them get repopulated to their default createscene values on one’s next “visit” to the scene? Does this generally sound like a reasonable process to follow for a game where you can return to scenes?

Thanks very much for the input :slight_smile: [import]uid: 105707 topic_id: 19685 reply_id: 96671[/import]

Yes most of the modern languages Java and C# handle GC behind the scenes. I don’t know about C++ specifically but older languages did not have GC so you had to handle all of your memory management yourself.

For this next part please remember that I am still learning this as well :slight_smile:

As for the RPG I think you’re on the right track but there are some things to remember. The exitScene function would be where you want to save state variables so that you could reference them later. However you might run into a problem if you only reference them in the createScene function. the createScene function only runs if the scene does not exists or in other words if it had been garbage collected and complete destroyed. Since we want the GC to handle as much as it can automatically we can’t rely on that. In my thinking I would reference those variables in the enterScene function which you know would run everytime that you enter a scene. My hesitation in saying that is wondering if that would be to late. One thing that you will want to do is to dig through the storyboard API (http://developer.anscamobile.com/content/storyboard) and take a look at the various methods that they make available. Using the removeScene() function would be like calling the GC so the createScene function would be run every time. You could put the removeScene in your exitScene to ensure that it happened but also remember about preformance. What if a user turns right back around and enters the same scene? Is there going to be a lag even though they were just there? Those are some of the things that I’m trying to figure out.

As for unimportant values set all of them to nil in the exitScene function so that they are dealt with on a scene by scene basis. You can always reset the value of a variable but don’t wait until the destroyScene to do that. I would reserve destroyScene for things that you need to make sure happen when your app is shutdown such as closing DB connections, files, audio streams, etc that were local to that scene. You don’t want to GC a global variable :slight_smile:

Hope that helps. If I’m off anywhere or anyone wants to help clarify anything I’m fuzzy on I would much like the guidance as well!

Jason Presley
Twitter: @MeOnCoronaSDK
Blog: jasonpresleyjer2911.tumblr.com [import]uid: 136162 topic_id: 19685 reply_id: 96701[/import]

Jason, your insight has been remarkably helpful. You’ve painted a picture that really makes sense as far as the create and destroy functions relating to memory management and the enter and exit scene relating to what a player experiences.

My hesitation in saying that is wondering if that would be to late.

I think you may be right here. It’s been a bit since I’ve worked on my storyboard based project and seem to recal that I had to do a few things with the create scene function so that they would display correctly for the transition I had into the new scene… [import]uid: 105707 topic_id: 19685 reply_id: 97713[/import]

I just ran across this. It might help you with what you are trying to do. Just added to Corona build 2012.773 was the enterBegin and exitEnded events. enterBegin fires after create scene (if create scene even needs to fire which is one of the issues) but before the enterScene event. That means that you can put all of you code that needs to happen before the scene change into the enterBegin event and it will be called every time before the enterScene event. Note however that it is a newer build of the SDK so you might have to upgrade you SDK version to get it to work. Here is the link that explains the events.

http://blog.anscamobile.com/2012/03/storyboard-scene-events-explained/ [import]uid: 136162 topic_id: 19685 reply_id: 97961[/import]

Thanks for the heads up on that blog post. I had missed that and it looks like essential reading for working with the Storyboard API!

[import]uid: 105707 topic_id: 19685 reply_id: 99150[/import]