Jump to content

[TOPIC: topicViewTemplate]
[GLOBAL: userSmallPhoto]
Photo

Removing timers on scene change - help needed please
Started by stevejcummins Feb 24 2015 05:00 AM

- - - - -
3 replies to this topic
[TOPIC CONTROLS]
This topic has been archived. This means that you cannot reply to this topic.
[/TOPIC CONTROLS]
[modOptionsDropdown]
[/modOptionsDropdown]
[reputationFilter]
[TOPIC: post.html]
#1

stevejcummins

[GLOBAL: userInfoPane.html]
stevejcummins
  • Observer

  • 9 posts
  • Corona SDK

Hi,

I'm having problems with trying to cancel a timer if a scene is changed.

I have used the 'Bullets' sample code packaged with Corona as the basis for my attempt below. What the code is doing is basically having bats fly across the screen, related to a timer.

If the user stays on the page and lets the effect take place, all is fine.

However, if the user skips the page and continues on, the app crashes.

I'm guessing this is because I haven't cancelled the timer if the user moves on. How do I do that? Any help is really appreciated

Steve

 

 

module(..., package.seeall)
new = function ( params )
local ui = require ( "ui" )
local music = audio.loadSound("sounds/LegendTheme.mp3")
audio.stop( ) --music, {channel = 4}
local localGroup = display.newGroup()
---End of header-----
local background = display.newImage( "images/p19_background.jpg", true )
local physics = require("physics")
physics.start()
physics.setScale( 40 )
local batsound = audio.loadSound("sounds/P19_Bats.mp3")
local banshee = audio.loadSound("sounds/P19_Banshee.mp3")
local pagetext = display.newImage( "images/p19_text.png", true )
pagetext.x = 230
pagetext.y = 150
local bats = {}
local n = 0
local function throwBrick()
n = n + 1
bats[n] = display.newImage( "images/p19_bat.png", -150, 600)
physics.addBody( bats[n], { density=-20, friction=0, bounce=0 } )
--remove the "isBullet" setting below to see the brick pass through cans without colliding!
bats[n].isBullet = true
bats[n].angularVelocity = 10
bats[n]:applyForce( 2400, 0, bats[n].x, bats[n].y )
end
function start()
-- throw 3 bats
timerStash.newTimer = timer.performWithDelay( 500, throwBrick, 4)
audio.play( batsound, { channel = 0, loops = 0 } )
audio.play( banshee, {channel = 0, loops = 0} )
end
-- wait 800 milliseconds, then call start function above
timerStash.newTimer = timer.performWithDelay( 3000, start )
local function throwBrick2()
n = n + 1
bats[n] = display.newImage( "images/p19_bat.png", -150, 300)
physics.addBody( bats[n], { density=-20, friction=0, bounce=0 } )
--remove the "isBullet" setting below to see the brick pass through cans without colliding!
bats[n].isBullet = true
bats[n].angularVelocity = 10
bats[n]:applyForce( 2400, 0, bats[n].x, bats[n].y )
end
function start2()
-- throw 3 bats
timerStash.newTimer = timer.performWithDelay( 500, throwBrick2, 4)
end
-- wait 800 milliseconds, then call start function above
timerStash.newTimer = timer.performWithDelay( 3150, start2 )
--[[ local function throwBrick3()
n = n + 1
bats[n] = display.newImage( "images/p19_bat.png", -150, 400)
physics.addBody( bats[n], { density=-20, friction=0, bounce=0 } )
--remove the "isBullet" setting below to see the brick pass through cans without colliding!
bats[n].isBullet = true
bats[n].angularVelocity = 10
bats[n]:applyForce( 2400, 0, bats[n].x, bats[n].y )
end
function start(event)
-- throw 3 bats
timerStash.newTimer = timer.performWithDelay( 500, throwBrick3, 1)
end
-- wait 800 milliseconds, then call start function above
timerStash.newTimer = timer.performWithDelay( 3300, start )
local function throwBrick4()
n = n + 1
bats[n] = display.newImage( "images/p19_bat.png", -150, 500)
physics.addBody( bats[n], { density=-20, friction=0, bounce=0 } )
--remove the "isBullet" setting below to see the brick pass through cans without colliding!
bats[n].isBullet = true
bats[n].angularVelocity = 10
bats[n]:applyForce( 2400, 0, bats[n].x, bats[n].y )
end
function start(event)
-- throw 3 bats
timerStash.newTimer = timer.performWithDelay( 500, throwBrick3, 1)
end
-- wait 800 milliseconds, then call start function above
timerStash.newTimer = timer.performWithDelay( 3450, start )
local function sound(event)
audio.play( bansheesound, { channel = 0, loops = 0} )
end
timerStash.newTimer = timer.performWithDelay(1000, sound, false ) --]]
---- Common UI controls---
local mainmenut = function ( event )
if event.phase == "release" then
director:changeScene( "chap3toc", "fade" )
display.remove(bats)
--display.remove(banshee)
audio.stop()
audio.dispose()
--bansheesound=nil
physics.stop()
end
end
local mainmenu = ui.newButton{
default = "images/ui_p19.png",
over = "images/ui_p19.png",
onEvent = mainmenut,
id = "mainmenu"
}
mainmenu.x = display.contentWidth /2
mainmenu.y = 994
local btfort = function ( event )
if event.phase == "release" then
director:changeScene( "page20", "crossfade" )
display.remove(bats)
audio.stop()
audio.dispose()
--bansheesound=nil
physics.stop()
end
end
local btfor = ui.newButton{
default = "images/arrow.png",
over = "images/arrow2.png",
onEvent = btfort,
id = "btfor"
}
local btbackt = function ( event )
if event.phase == "release" then
director:changeScene( "page18", "crossfade" )
display.remove(bats)
audio.stop()
audio.dispose()
--bansheesound=nil
physics.stop()
end
end
local btback = ui.newButton{
default = "images/back.png",
over = "images/back2.png",
onEvent = btbackt,
id = "btback"
}
btfor.x = 710
btfor.y = 975
btback.x = 58
btback.y = 975
----End Common UI Controls
---Footer and placing of localGroup Assets --
local initVars = function ()
localGroup:insert ( background )
--localGroup:insert ( bats )
localGroup:insert ( pagetext )
localGroup:insert( btfor )
localGroup:insert( btback )
localGroup:insert( mainmenu )
--
end
initVars()
return localGroup
end
----END----



[TOPIC: post.html]
#2

schroederapps

[GLOBAL: userInfoPane.html]
schroederapps
  • Contributor

  • 411 posts
  • Corona SDK

A few things that may help:

 

  1. While I don't see the creation of the "timerStash" table in the code you posted, it's good that you are already organizing your timers into a table - that will help you achieve what you want to do.
  2. HOWEVER, each time you create a new timer, you are re-using the variable timerStash.newTimer to hold that timer. This is bad, because it effectively eliminates your ability to do anything with previously-created timers (like cancel them!)
  3. SO: to start with, stop creating new timers by declaring timerStash.newTimer = timer.performWithDelay() - INSTEAD, try this method:
    timerStash[#timerStash+1] = timer.performWithDelay()
    
  4. Now that all your timers have their own variables assigned to them, you can cancel all your timers at once when changing scenes by inserting the following code: 
  5. for i = 1, #timerStash do
       if timerStash[i] ~= nil then timer.cancel(timerStash[i]) end
    end
    

 

 

The above steps should accomplish what you want to get done. But I would suggest you go and vote up this feature request: http://feedback.coronalabs.com/forums/188732-corona-sdk-feature-requests-feedback/suggestions/5067720-tag-support-for-timers-same-method-as-transitions 

 

That feature request is for the timer API to catch up with the more recent transition API, which supports tagging and global pause/cancel/resume support. If that feature gets implemented, then we'd be able to easily cancel all timers at once (or a subset of tagged timers) without the need to keep them all in a table. It'd be a much better solution - so go vote for it! :)

 

Good luck!



[TOPIC: post.html]
#3

schroederapps

[GLOBAL: userInfoPane.html]
schroederapps
  • Contributor

  • 411 posts
  • Corona SDK

Hi Steve,

 

Just wanted to share that I was inspired by this post to create my own "timer 2.0" library that is a drop-in replacement for the timer library, that adds some great new features (basically the ones that are requested in the feature request I linked to):

 

  • You can add tags to timers when creating them using timer.performWithDelay()
  • You can pause, resume, or cancel all active timers at once by simply calling timer.pause(), timer.resume(), or timer.cancel() with no arguments.
  • You can pause, resume, or cancel all timers with a specific tag by passing that tag as a argument to timer.pause(), timer.resume(), or timer.cancel()
  • You can exclude specific timers from the "catch-all" pause/resume/cancel functions by adding "true" as an argument to timer.performWithDelay, setting that timer's "exclude" parameter to true.

I've written a blog post on my site detailing how to use the updated library, and you can download the library's lua file from that post. Here's a link: http://www.jasonschroeder.com/2015/02/25/timer-2-0-library-for-corona-sdk/

 

Hope you find it useful!



[TOPIC: post.html]
#4

stevejcummins

[GLOBAL: userInfoPane.html]
stevejcummins
  • Observer

  • 9 posts
  • Corona SDK

Thanks so much for this.

Really appreciate your help on this.

Fantastic work

:)




[topic_controls]
[/topic_controls]