Question

I'm trying to spawn objects above screen height to fall down. The code I've written so far works, but when i lets the scene run out, go back and start the level again the scene have 2 issues: 1. The spawn function "spawnObjects" seems to fire twice every 0.5 sec but only sometimes, but always at the second run. More than often console looks it's firing 3 (liike they're stacking) 2. At the second run the function that should run when timer goes to 0 or less isn't.

This is my code, it might be chunky and have values and what not in odd places. This is because I've been struggling with the timers and now this(still kinda timers) for some days now and I've tried so many different things. Hope anybody can see what I'm doing wrong, if you have a better solution for a countDown timer and/or way of spawning the objects then I'll try wwhatever.

local composer = require( "composer" )
local scene = composer.newScene()
local myData = require( "myData" )
local physics = require("physics")
physics.setDrawMode( "hybrid" )
-- forward references
local w = display.actualContentWidth
local h = display.actualContentHeight
local dropCount = 0
local spawnShit = 0
local spawnTime = 17
local countdownTimer
local score = 0
local countNumber = 10
local countDownNumber = 10
local scoreT = display.newText( {text="Score: "..score, font=system.nativeSystemFont, fontSize=14,} )
scoreT.x = w * 0.5
scoreT.y = h * 0.1
local countDownText = display.newText( {text="", font=system.nativeSystemFont, fontSize=14} )
countDownText.x = w * 0.5
countDownText.y = h * 0.2
local drop01 = display.newImage("drop01.png")
drop01.x = -100
local drop02 = display.newImage("drop02.png")
drop02.x = -100
local drop03 = display.newImage("drop03.png")
drop03.x = -100
local drop04 = display.newImage("drop04.png")
drop04.x = -100
local timerSpawn

-- Display objects
local background = display.newImage( "bluebg.png" )
background.x = w*0.5
background.y = h*0.5
background.width = w 
background.height = h 

local bckBtn = display.newText({text="<--BACK", font=system.nativeSystemFont, fontSize=14})
bckBtn.x = 50
bckBtn.y = 20


local egon = display.newImage( "Egon.png" )
egon.x = w*0.5
egon.y = h*0.85
egon.width = 100
egon.height = 97



--functions

function goBack (event)

    if "began" == event.phase then

        elseif event.phase == "ended" then

    composer.gotoScene("select", "fade", 500)

    end




    return true

end

 function moveEgon (event)
    egon.x = event.x
 end

------------------------------------------------vvv---------------------------------------------------
------------------------------------------------vvv---------------------------------------------------
------------------------------------------------vvv---------------------------------------------------
 function spawnObjects (event)

        dropCount = math.random(1,4)



        if stopTimer == 1 then
            timer.cancel(timerSpawn)
            timerSpawn = nil
            spawnShit = nil
        end
        if spawnShit == 1 then
            print( 'spawnShit' )
            if dropCount == 1 then
            -- Drop01 function and settings
            drop01 = display.newImage( "drop01.png" )
            drop01.x = math.random(10, 470)
            drop01.y = 40
            drop01.width = 50
            drop01.height = 50
            drop01.myName = "01"
            physics.addBody( drop01, "dynamic", {density=0.1, friction=0.1, bounce=0.8 } )
            elseif dropCount == 2 then
                --Do shit for drop02
            drop02 = display.newImage( "drop02.png" )
            drop02.x = math.random(10, 470)
            drop02.y = 40
            drop02.width = 50
            drop02.height = 50
            drop02.myName = "02"
                physics.addBody( drop02, "dynamic", {density=0.1, friction=0.1, bounce=0.8 } )
                elseif dropCount == 3 then
            drop03 = display.newImage( "drop03.png" )
            drop03.x = math.random(10, 470)
            drop03.y = 40
            drop03.width = 50
            drop03.height = 50
            drop03.myName = "03"
            physics.addBody( drop03, "dynamic", {density=0.9, friction=0.1, bounce=0.8 } )
                    elseif dropCount == 4 then
            drop04 = display.newImage( "drop04.png" )
            drop04.x = math.random(10, 470)
            drop04.y = 40
            drop04.width = 50
            drop04.height = 50
            drop04.myName = "04"
            physics.addBody( drop04, "dynamic", {density=0.9, friction=0.1, bounce=0.8 } )
            end

        end
        return true
end

---------------------------------------------------------------------------------------------------
---------------------------------------------------------------------------------------------------
---------------------------------------------------------------------------------------------------

 function onCollision (event)

    if "began" == event.phase then
        --v--do shit when touching surface

    if event.other.myName == "01" then
        -- Do shit for drop01 -- 
        -- Change score, powersups etc
        event.other:removeSelf( )
    end

        if event.other.myName == "02" then
            -- Do shit for drop02 -- 
        -- Change score, powersups etc
        event.other:removeSelf( )
    end

        if event.other.myName == "03" then 
            -- Do shit for drop03 -- 
        -- Change score, powersups etc
        event.other:removeSelf( )

        end

        if event.other.myName == "04" then
            -- Do shit for drop04 -- 
        -- Change score, powersups etc
        event.other:removeSelf( )
        end

    elseif "ended" == event.phase then 
    -- Do shit when leaving surfaces
end 

    return true

 end
------------------------------------------------vvv---------------------------------------------------
------------------------------------------------vvv---------------------------------------------------
------------------------------------------------vvv---------------------------------------------------
function showCountDown (event)
-- Condition to show and hide countdown
    if countDownNumber <= 0  then
        timer.cancel(event.source)
        countDownTimer = nil
        spawnShit = 0
        print( 'NO MORE SPAAAAAAAAAAAAAAAWWNS' )
    else 
        countDownNumber = countDownNumber -1 
        countDownText.text = countDownNumber
         spawnShit = 1
    end
    return true
end

---------------------------------------------------------------------------------------------------
---------------------------------------------------------------------------------------------------
---------------------------------------------------------------------------------------------------

--function scene:create( event )
function scene:create( event )
    local sceneGroup = self.view

    -- Initialize the scene here.
    -- Example: add display objects to "sceneGroup", add touch listeners, etc

    --Listeners

    background:addEventListener( "touch", moveEgon )
    bckBtn:addEventListener( "touch", goBack )
    egon:addEventListener( "collision", onCollision )
    --SceneGroup insert
    sceneGroup:insert( background )
    sceneGroup:insert(egon)
    sceneGroup:insert(bckBtn)
    sceneGroup:insert(drop01)
    sceneGroup:insert(drop02)
    sceneGroup:insert(drop03)
    sceneGroup:insert(drop04)
    sceneGroup:insert(scoreT)
    sceneGroup:insert(countDownText)


    end


-- "scene:show()"
function scene:show( event )

    local sceneGroup = self.view
    local phase = event.phase

    if ( phase == "will" ) then
        -- Called when the scene is still off screen (but is about to come on screen).
    elseif ( phase == "did" ) then
        -- Called when the scene is now on screen.
        -- Insert code here to make the scene come alive.
        -- Example: start timers, begin animation, play audio, etc.
        physics.start( )
        timercount = 10



            -- ADD physic bodies ----
            physics.addBody( egon, "static", {density=0.1, friction=0.1, bounce=0.8 } )
            countDownNumber = 10
            countdownTimer = timer.performWithDelay( 1000, showCountDown, countNumber )
            ----------- Timers ------------
            timerSpawn = timer.performWithDelay(500, spawnObjects, 0 )


    end
end


-- "scene:hide()"
function scene:hide( event )

    local sceneGroup = self.view
    local phase = event.phase

    if ( phase == "will" ) then
        -- Called when the scene is on screen (but is about to go off screen).
        -- Insert code here to "pause" the scene.
        -- Example: stop timers, stop animation, stop audio, 
        --timer.pause( timerSpawn )
        physics.stop()

        spawnShit = 0
        timerSpawn = nil
        countdownTimer = nil
        physics.removeBody( egon )



    elseif ( phase == "did" ) then
        -- Called immediately after scene goes off screen.
    end
end


-- "scene:destroy()"
function scene:destroy( event )

    local sceneGroup = self.view

    -- Called prior to the removal of scene's view ("sceneGroup").
    -- Insert code here to clean up the scene.
    -- Example: remove display objects, save state, etc.
    bckBtn:removeEventListener("touch", goBack )
    egon:removeEventListener("touch", moveEgon )

end



-- -------------------------------------------------------------------------------

-- Listener setup
scene:addEventListener( "create", scene )
scene:addEventListener( "show", scene )
scene:addEventListener( "hide", scene )
scene:addEventListener( "destroy", scene )

-- -------------------------------------------------------------------------------

return scene
Was it helpful?

Solution

When your scene:show(), you execute

timerSpawn = timer.performWithDelay(500, spawnObjects, 0 )

which will cause spawObjects to be called every 0.5 seconds indefinitely (ie until application exits, or timer is cancelled or paused). This is ok except that when you come back to that scene, that line gets executed again, which will cause a new timer to be created, and timeSpawn now references the new timer. So now you'll have two timers firing at every 0.5 seconds approx. When you leave scene and come back again, you will have 3, etc. The fact that timerSpawn gets set to reference a new timer does not stop the old timer. You probably should pause timerSpawn when the scene gets hidden; then in the show(), you should only create the timer if it doesn't already exist:

function scene:show( event )
        ....
        ----------- Timers ------------
        countDownNumber = 10
        if countdownTimer == nil then
            countdownTimer = timer.performWithDelay( 1000, showCountDown, countNumber )
        else 
            timer.resume(countownTimer)
        end
        if timerSpawn == nil then
            timerSpawn = timer.performWithDelay(500, spawnObjects, 0 )
        else 
            timer.resume(timerSpawn)
        end
end

function scene:hide( event )
    ...
    if ( phase == "will" ) then
        timer.pause( timerSpawn )
        timer.pause( countdownTimer )
        -- NO: 
        -- timerSpawn = nil
        -- countdownTimer = nil
        ...
    end
end
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top