Timer not resuming properly after timer.pause()

Hi community,

I’m stuck with a really weird timer.pause() and timer.resume() problem.

I got a square jumping on the ground every 2 seconds using timer.performWithDelay and applyFore for the jump.

When I try to pause the timer, and then resume, it sometimes happens that the resuming will not continue where it paused, but perform the applyForce immediately.

It happens more often, when I try to pause in the first 1 second of the 2 second sequence.

I’ve also measured the actual milliseconds between the jumps and it varies between 900 and 2000 ms (where it should be always 2000ms ± 30ms).

Please help, I’m stuck on the problem for days now…

See below for the code - if you try that yourself:

First, please watch how the square jumps up and down to see that it happens about every 2 seconds without pauseing.

Then, try to pause the game (just click anywhere) when the square is on the way up (also see attachment for the exact moment).

Then wait a bit and resume (again, click anywhere) and check if the square jumps earlier than it should be.

If you don’t see the problem immediately, try to pause and resume several times.

Here’s the code:

local physics = require "physics" physics.setScale( 90 ) physics.start() local startPauseTime = 0 local endPauseTime = 0 local totalPauseTime = 0 local lastForceTime = 0 local currentForceTime = 0 ground = display.newRect( -100,display.contentHeight-82, display.contentWidth+100, 82+100 ) ground:setFillColor(0,0.3,0) ground.anchorX = 0 ground.anchorY = 0 physics.addBody( ground, "static", { friction=0.3} ) brick = display.newRect(100,100,100,100) --brick.anchorY = 0 brick.x = display.contentWidth / 2 brick.y = display.contentHeight/2-35 physics.addBody( brick, "dynamic", {density = 1.0, friction=0.9}) testTimer = timer.performWithDelay(2000, function ()                                                 print ("Time between applyForce: " .. system.getTimer() - lastForceTime - totalPauseTime)                                                 totalPauseTime = 0                                                 --print ("Brick y position: "..brick.y)                                                 brick:applyForce(0, -250, brick.x, brick.y)                                                 lastForceTime = system.getTimer()                                          end,0) bg = display.newRect( -100,-100, display.contentWidth, display.contentHeight ) bg.x, bg.y = display.contentWidth / 2, display.contentHeight / 2 bg:setFillColor(0.3,0.3,0.3) bg:toBack() local function pauseTestTimer()     local t = timer.pause(testTimer)     --print ("pause time: "..t)     startPauseTime = system.getTimer() end local function resumeTestTimer()     local t = timer.resume(testTimer)     --print ("resume time: "..t)     endPauseTime = system.getTimer()     totalPauseTime = endPauseTime - startPauseTime     --print ("Time between Start and End of Pause: " .. totalPauseTime) end bg:addEventListener("touch", function(event)     if (event.phase=="began") then         if (pause==true) then             pause=false             resumeTestTimer()             physics.start()             return true         else             pause=true             pauseTestTimer()             physics.pause()             return true         end     elseif (event.phase=="ended") then         return false     end end)

Warning.  I made a lot of changes to your code so it would be more self-contained:

local physics = require "physics" physics.setScale( 90 ) physics.start() local ground = display.newRect( -100,display.contentHeight-82, display.contentWidth+100, 82+100 ) ground:setFillColor(0,0.3,0) ground.anchorX = 0 ground.anchorY = 0 physics.addBody( ground, "static", { friction=0.3} ) local brick = display.newRect(100,100,100,100) --brick.anchorY = 0 brick.x = display.contentWidth / 2 brick.y = display.contentHeight/2-35 physics.addBody( brick, "dynamic", {density = 1.0, friction=0.9}) brick.forceTime = 0 -- Time Force applied brick.remainingTime = 0 -- Time remaing in this timer cycle if pausing brick.pauseTime = 0 -- Time we paused brick.elapsedTime = 0 -- Time we spend paused brick.timerPeriod = 2000 -- Time between forces (not including paused time) brick.timer = function( self ) print ("Time since last applyForce: " .. system.getTimer() - self.forceTime - self.elapsedTime ) self.totalPauseTime = 0 self:applyForce(0, -250, self.x, self.y) self.forceTime = system.getTimer() self.remainingTime = 0 self.pauseTime = 0 self.elapsedTime = 0 self.myTimer = timer.performWithDelay( self.timerPeriod, brick ) end brick.pauseTestTimer = function( self ) self.pauseTime = system.getTimer() self.remainingTime = self.timerPeriod - (self.pauseTime - self.forceTime) timer.cancel( self.myTimer ) self.myTimer = nil physics.pause() end brick.resumeTestTimer = function( self ) self.elapsedTime = system.getTimer() - self.pauseTime self.myTimer = timer.performWithDelay( self.remainingTime, brick ) physics.start() end local bg = display.newRect( -100,-100, display.contentWidth, display.contentHeight ) bg.x, bg.y = display.contentWidth / 2, display.contentHeight / 2 bg:setFillColor(0.3,0.3,0.3) bg:toBack() bg.paused = false bg.touch = function( self, event ) local phase = event.phase local time = event.time if( phase == "began" ) then if( self.paused == true ) then self.paused = false brick:resumeTestTimer() else self.paused = true brick:pauseTestTimer() end return true elseif( phase == "ended" ) then return false end return false end bg:addEventListener( "touch" ) brick.myTimer = timer.performWithDelay( brick.timerPeriod, brick )

Thanks a lot for the reply. This works much better! (Although I’m not yet sure why, but probably I’ll figure that out…)
But also using this code, the resume is not working properly always: If you pause now twice: once when the square is nearly at the top and the second time when the square nearly hits the ground, you’ll see that the square will try to jump earlier than it should.
Any ideas?

Edit: Why don’t you use timer.pause() at all in your code?

Thanks again roaminggamer!

I’ve made a few changes so it will also work with multiple pauses - now it works totally correctly :slight_smile: Finally!

See below for the finale code.

What is still strange - the timer.pause() function seems to be buggy when you try to pause a timer.performWithDelay with infinite iterations.

local physics = require "physics" physics.setScale( 90 ) physics.start() local ground = display.newRect( -100,display.contentHeight-82, display.contentWidth+100, 82+100 ) ground:setFillColor(0,0.3,0) ground.anchorX = 0 ground.anchorY = 0 physics.addBody( ground, "static", { friction=0.3} ) local brick = display.newRect(100,100,100,100) --brick.anchorY = 0 brick.x = display.contentWidth / 2 brick.y = display.contentHeight/2-35 physics.addBody( brick, "dynamic", {density = 1.0, friction=0.9}) brick.forceTime         = 0 -- Time Force applied brick.remainingTime     = 0 -- Time remaing in this timer cycle if pausing brick.pauseTime         = 0 -- Time we paused brick.elapsedTime       = 0 -- Time we spend paused brick.timerPeriod       = 2000 -- Time between forces (not including paused time) brick.timer = function( self )     print ("Time since last applyForce: " .. system.getTimer() - self.forceTime - self.elapsedTime )     self.totalPauseTime = 0     self:applyForce(0, -250, self.x, self.y)     self.forceTime = system.getTimer()     self.remainingTime = 0     self.pauseTime = 0     self.elapsedTime = 0     self.myTimer = timer.performWithDelay( self.timerPeriod, brick ) end brick.pauseTestTimer = function( self )     self.pauseTime = system.getTimer()     print (self.pauseTime .. " - " .. self.forceTime)     self.remainingTime = self.timerPeriod - (self.pauseTime - self.forceTime) + self.elapsedTime     print (self.remainingTime)     timer.cancel( self.myTimer )     self.myTimer = nil     physics.pause() end brick.resumeTestTimer = function( self )     self.elapsedTime = self.elapsedTime + system.getTimer() - self.pauseTime     self.myTimer = timer.performWithDelay( self.remainingTime, brick )     physics.start() end local bg = display.newRect( -100,-100, display.contentWidth, display.contentHeight ) bg.x, bg.y = display.contentWidth / 2, display.contentHeight / 2 bg:setFillColor(0.3,0.3,0.3) bg:toBack() bg.paused = false bg.touch = function( self, event )     local phase = event.phase     local time = event.time     if( phase == "began" ) then         if( self.paused == true ) then             self.paused = false             brick:resumeTestTimer()                                 else             self.paused = true             brick:pauseTestTimer()                                 end         return true     elseif( phase == "ended" ) then         return false     end     return false end bg:addEventListener( "touch" ) brick.myTimer = timer.performWithDelay( brick.timerPeriod, brick )

Warning.  I made a lot of changes to your code so it would be more self-contained:

local physics = require "physics" physics.setScale( 90 ) physics.start() local ground = display.newRect( -100,display.contentHeight-82, display.contentWidth+100, 82+100 ) ground:setFillColor(0,0.3,0) ground.anchorX = 0 ground.anchorY = 0 physics.addBody( ground, "static", { friction=0.3} ) local brick = display.newRect(100,100,100,100) --brick.anchorY = 0 brick.x = display.contentWidth / 2 brick.y = display.contentHeight/2-35 physics.addBody( brick, "dynamic", {density = 1.0, friction=0.9}) brick.forceTime = 0 -- Time Force applied brick.remainingTime = 0 -- Time remaing in this timer cycle if pausing brick.pauseTime = 0 -- Time we paused brick.elapsedTime = 0 -- Time we spend paused brick.timerPeriod = 2000 -- Time between forces (not including paused time) brick.timer = function( self ) print ("Time since last applyForce: " .. system.getTimer() - self.forceTime - self.elapsedTime ) self.totalPauseTime = 0 self:applyForce(0, -250, self.x, self.y) self.forceTime = system.getTimer() self.remainingTime = 0 self.pauseTime = 0 self.elapsedTime = 0 self.myTimer = timer.performWithDelay( self.timerPeriod, brick ) end brick.pauseTestTimer = function( self ) self.pauseTime = system.getTimer() self.remainingTime = self.timerPeriod - (self.pauseTime - self.forceTime) timer.cancel( self.myTimer ) self.myTimer = nil physics.pause() end brick.resumeTestTimer = function( self ) self.elapsedTime = system.getTimer() - self.pauseTime self.myTimer = timer.performWithDelay( self.remainingTime, brick ) physics.start() end local bg = display.newRect( -100,-100, display.contentWidth, display.contentHeight ) bg.x, bg.y = display.contentWidth / 2, display.contentHeight / 2 bg:setFillColor(0.3,0.3,0.3) bg:toBack() bg.paused = false bg.touch = function( self, event ) local phase = event.phase local time = event.time if( phase == "began" ) then if( self.paused == true ) then self.paused = false brick:resumeTestTimer() else self.paused = true brick:pauseTestTimer() end return true elseif( phase == "ended" ) then return false end return false end bg:addEventListener( "touch" ) brick.myTimer = timer.performWithDelay( brick.timerPeriod, brick )

Thanks a lot for the reply. This works much better! (Although I’m not yet sure why, but probably I’ll figure that out…)
But also using this code, the resume is not working properly always: If you pause now twice: once when the square is nearly at the top and the second time when the square nearly hits the ground, you’ll see that the square will try to jump earlier than it should.
Any ideas?

Edit: Why don’t you use timer.pause() at all in your code?

Thanks again roaminggamer!

I’ve made a few changes so it will also work with multiple pauses - now it works totally correctly :slight_smile: Finally!

See below for the finale code.

What is still strange - the timer.pause() function seems to be buggy when you try to pause a timer.performWithDelay with infinite iterations.

local physics = require "physics" physics.setScale( 90 ) physics.start() local ground = display.newRect( -100,display.contentHeight-82, display.contentWidth+100, 82+100 ) ground:setFillColor(0,0.3,0) ground.anchorX = 0 ground.anchorY = 0 physics.addBody( ground, "static", { friction=0.3} ) local brick = display.newRect(100,100,100,100) --brick.anchorY = 0 brick.x = display.contentWidth / 2 brick.y = display.contentHeight/2-35 physics.addBody( brick, "dynamic", {density = 1.0, friction=0.9}) brick.forceTime         = 0 -- Time Force applied brick.remainingTime     = 0 -- Time remaing in this timer cycle if pausing brick.pauseTime         = 0 -- Time we paused brick.elapsedTime       = 0 -- Time we spend paused brick.timerPeriod       = 2000 -- Time between forces (not including paused time) brick.timer = function( self )     print ("Time since last applyForce: " .. system.getTimer() - self.forceTime - self.elapsedTime )     self.totalPauseTime = 0     self:applyForce(0, -250, self.x, self.y)     self.forceTime = system.getTimer()     self.remainingTime = 0     self.pauseTime = 0     self.elapsedTime = 0     self.myTimer = timer.performWithDelay( self.timerPeriod, brick ) end brick.pauseTestTimer = function( self )     self.pauseTime = system.getTimer()     print (self.pauseTime .. " - " .. self.forceTime)     self.remainingTime = self.timerPeriod - (self.pauseTime - self.forceTime) + self.elapsedTime     print (self.remainingTime)     timer.cancel( self.myTimer )     self.myTimer = nil     physics.pause() end brick.resumeTestTimer = function( self )     self.elapsedTime = self.elapsedTime + system.getTimer() - self.pauseTime     self.myTimer = timer.performWithDelay( self.remainingTime, brick )     physics.start() end local bg = display.newRect( -100,-100, display.contentWidth, display.contentHeight ) bg.x, bg.y = display.contentWidth / 2, display.contentHeight / 2 bg:setFillColor(0.3,0.3,0.3) bg:toBack() bg.paused = false bg.touch = function( self, event )     local phase = event.phase     local time = event.time     if( phase == "began" ) then         if( self.paused == true ) then             self.paused = false             brick:resumeTestTimer()                                 else             self.paused = true             brick:pauseTestTimer()                                 end         return true     elseif( phase == "ended" ) then         return false     end     return false end bg:addEventListener( "touch" ) brick.myTimer = timer.performWithDelay( brick.timerPeriod, brick )