Extreme lag and occasional moments of speed-ups

I am not sure if the title made any sense, but I am near the end of my video game, there are two problems left, and I am hoping you could give some suggestions to fix them. 

Occasionally, the game becomes very slow and laggy and I am not sure why, and at other times the game “speeds up”, image sheets, timers, and functions seeming to occur at double speed, I have no clue what is causing this and I am sure I removed all my event listeners and timers, if I missed one or two please let me know. This is my level1.lua:

local composer = require("composer") local scene = composer.newScene() local score = require("score") local json = require("json") local myData = require("mydata") local loadsave = require("loadsave") local physics = require("physics") physics.start(); physics.pause(); physics.setGravity(0, 20) local physicsData = (require "enemies").physicsData(1.0) -- ----------------------------------------------------------------------------------- -- Code outside of the scene event functions below will only be executed ONCE unless -- the scene is removed entirely (not recycled) via "composer.removeScene()" -- ----------------------------------------------------------------------------------- local mRand = math.random local screenW, screenH, halfW = display.actualContentWidth, display.actualContentHeight, display.contentCenterX local vx, vy local lives = {} -- table that will hold the lives object local livesCount = 4 local character local points = 0 local pointsText local highestPointsText local group local specialGroup local currentScore local spawnTable = {} local spawnEnemiesTimer local moveEnemiesTimer local horizon local horizon2 local mountainback local mountainback2 local mountain local mountain2 local trees local trees2 local temp local girlSheetData = {width = 100, height = 126.5, numFrames = 10, sheetContentWidth = 500, sheetContentHeight = 253} local girl = graphics.newImageSheet("girl-running.png", girlSheetData) local girlSequenceData = { {name = "walking", start = 1, count = 10, time = 750, loopCount = 0} } local boySheetData = {width = 100, height = 135, numFrames = 10, sheetContentWidth = 500, sheetContentHeight = 270} local boy = graphics.newImageSheet("guy-running.png", boySheetData) local boySequenceData = { {name = "walking", start = 1, count = 10, time = 500, loopCount = 0} } --local enemy = {} --local timeCounter = 0 -- how much time has passed in the game --local enemyCounter = 0 -- number of enemies sent --local enemySendSpeed = 90 -- how often to send the enemies --local enemyTravelSpeed = 7000 -- how fast enemies travel across the screen --local enemyIncrementSpeed = 1 -- how much to increase the enemy speed --local enemyMaxSendSpeed = 55 local beetleSheetData = {width=166.67, height=106, numFrames=10, sheetContentWidth=500, sheetContentHeight=424} local scorpionSheetData = {width=169, height=108, numFrames=10, sheetContentWidth=1690, sheetContentHeight=108} local vultureSheetData = {width=121, height=117.25, numFrames=4, sheetContentWidth=121, sheetContentHeight=469} local beeSheetData = {width=86, height=81, numFrames=8, sheetContentWidth=688, sheetContentHeight=81} local beetle = graphics.newImageSheet("beetle-walking2.png", beetleSheetData) local scorpion = graphics.newImageSheet("scorpion-walking.png", scorpionSheetData) local vulture = graphics.newImageSheet("vulture-flying.png", vultureSheetData) local bee = graphics.newImageSheet("bee-flying.png", beeSheetData) local scorpionSequenceData = { {name="moving", start=1, count=10, time=1000, loopCount=0} } local beetleSequenceData = { {name="moving", start=1, count=10, time=1000, loopCount=0} } local vultureSequenceData = { {name="flapping", start=1, count=4, time=500, loopCount=0} } local beeSequenceData = { {name="buzzing", start=1, count=8, time=500, loopCount=0} } -- ----------------------------------------------------------------------------------- -- Scene event functions -- ----------------------------------------------------------------------------------- -- create() function scene:create( event ) local sceneGroup = self.view -- Code here runs when the scene is first created but has not yet appeared on screen horizon = display.newImageRect("Sprite Sheets and Projects/Mountains/PALALLAX/horizon(5).png", 1425, 950) horizon.x = \_CX horizon.y = \_CY horizon.value = 0.2 horizon2 = display.newImageRect("Sprite Sheets and Projects/Mountains/PALALLAX/horizon(5).png", 1425, 950) horizon2.x = horizon.width \* 1.4 horizon2.y = \_CY horizon2.value = 0.2 mountainback = display.newImageRect("Sprite Sheets and Projects/Mountains/PALALLAX/mountainback(4).png", 1425, 950) mountainback.x = \_CX mountainback.y = \_CY mountainback.value = 0.4 mountainback2 = display.newImageRect("Sprite Sheets and Projects/Mountains/PALALLAX/mountainback(4).png", 1425, 950) mountainback2.x = mountainback.width \* 1.4 mountainback2.y = \_CY mountainback2.value = 0.4 mountain = display.newImageRect("Sprite Sheets and Projects/Mountains/PALALLAX/mountain(3).png", 1425, 950) mountain.x = \_CX mountain.y = \_CY mountain.value = 1 mountain2 = display.newImageRect("Sprite Sheets and Projects/Mountains/PALALLAX/mountain(3).png", 1425, 950) mountain2.x = mountain.width \* 1.4 mountain2.y = \_CY mountain2.value = 1 trees = display.newImageRect("Sprite Sheets and Projects/Mountains/PALALLAX/trees(2).png", 1425, 950) trees.x = trees.width \* 1.4 trees.y = \_CY trees.value = 5 trees2 = display.newImageRect("Sprite Sheets and Projects/Mountains/PALALLAX/trees(2).png", 1425, 950) trees2.x = trees.width \* 1.4 trees2.y = \_CY trees2.value = 5 ground = display.newImageRect("Sprite Sheets and Projects/Mountains/PALALLAX/ground(1).png", 1425, 950) ground.x = \_CX ground.y = \_CY ground.id = "ground" local groundShape = { -halfW \* 1.4, ground.height \* 0.32, halfW \* 1.4, ground.height \* 0.32, halfW \* 1.4, ground.height \* 0.52, -halfW \* 1.4, ground.height \* 0.52} physics.addBody( ground, "static", { friction=1, bounce = 0, shape=groundShape }) function scrollMountains(self,event) if self.x \< -self.width \* 0.6 then self.x = self.width \* 1.32 else self.x = self.x - self.value end end for i=1, livesCount do lives[i] = display.newImageRect(scene.view, "heart.png", 50, 50) lives[i].x = \_L + (i \* 65) - 25 lives[i].y = \_T + 50 end local player = json.decode(composer.getVariable( "player" )) if (player.myType == "boyCharacter") then character = display.newSprite(boy, boySequenceData) elseif (player.myType == "girlCharacter") then character = display.newSprite(girl, girlSequenceData) end character.y = \_CY - (character.height \* 0.3) character.id = "character" physics.addBody(character, "dynamic", {bounce = 0}) character.isFixedRotation = true function getVelocities() vx, vy = character:getLinearVelocity() end function endJump() character:applyForce(0, 0, self.x, self.y) end function touchScreen(event) if (event.phase == "began") then if (vy \> -25 and vy \< 25) then character:applyForce(0, -85, self.x, self.y) timer.performWithDelay(500, endJump, 1) end end end physics.setDrawMode("hybrid") group = display.newGroup() specialGroup = display.newGroup() function updateScore() points = points + 15 pointsText.text = string.format("Score: %d", points) if points \>= 30 then myData.settings.unlockedLevels = 2 loadsave.saveTable( myData.settings, "settings.json" ) end end function specialUpdateScore() points = points + 0 pointsText.text = string.format("Score: %d", points) end function highScore() currentScore = points if currentScore \> score.get() then score.set(currentScore) end score.save() end function spawnEnemies() temp = math.random(1, 4) enemy = display.newSprite(beetle, beetleSequenceData) enemy.x = \_R + 100 enemy.y = \_CY enemy.hasBeenScored = false physics.addBody(enemy, "dynamic", physicsData:get("beetle")) enemy.xScale = -1 enemy.id = "enemy" enemy.isFixedRotation = true enemy:play() group:insert(enemy) enemy2 = display.newSprite(vulture, vultureSequenceData) enemy2.x = \_R + 100 enemy2.y = \_CY - (enemy2.height \* 0.25) enemy2.hasBeenScored = false physics.addBody(enemy2, "dynamic", physicsData:get("vulture")) enemy2.xScale = -1 enemy2.gravityScale = -0.01 enemy2.id = "enemy2" enemy2.isFixedRotation = true enemy2:play() specialGroup:insert(enemy2) enemy3 = display.newSprite(scorpion, scorpionSequenceData) enemy3.x = \_R + 100 enemy3.y = \_CY enemy3.hasBeenScored = false physics.addBody(enemy3, "dynamic", physicsData:get("scorpion")) enemy3.xScale = -1 enemy3.id = "enemy3" enemy3.isFixedRotation = true enemy3:play() group:insert(enemy3) enemy4 = display.newSprite(bee, beeSequenceData) enemy4.x = \_R + 100 enemy4.y = \_CY - (enemy4.height \* 0.25) enemy4.hasBeenScored = false physics.addBody(enemy4, "dynamic", physicsData:get("bee")) enemy4.xScale = -1 enemy4.gravityScale = -0.01 enemy4.id = "enemy4" enemy4.isFixedRotation = true enemy4:play() specialGroup:insert(enemy4) if temp == 1 then enemy2:removeSelf() enemy3:removeSelf() enemy4:removeSelf() elseif temp == 2 then enemy:removeSelf() enemy3:removeSelf() enemy4:removeSelf() elseif temp == 3 then enemy:removeSelf() enemy2:removeSelf() enemy4:removeSelf() else enemy:removeSelf() enemy2:removeSelf() enemy3:removeSelf() end end function moveEnemies() for a = group.numChildren, 1, -1 do if group[a].x \< 100 then if group[a].hasBeenScored == false then updateScore() group[a].hasBeenScored = true end end if group[a].x \> \_L - 100 then group[a].x = group[a].x - 8 else group:remove(group[a]) end end for b = specialGroup.numChildren, 1, -1 do if specialGroup[b].x \< 100 then if specialGroup[b].hasBeenScored == false then specialUpdateScore() specialGroup[b].hasBeenScored = true end end if specialGroup[b].x \> \_L - 100 then specialGroup[b].x = specialGroup[b].x - 8 else specialGroup:remove(specialGroup[b]) end end end --pointsText = display.newText("Score: 0", 0, 0, "Helvetica", 40) --pointsText:setFillColor(0) --pointsText.x = \_R - 125 --pointsText.y = \_T + 50 pointsText = score.init({ fontSize = 40, font = "Helvetica", x = \_R - 125, y = \_T + 50, maxDigits = 5, leadingZeros = false, filename = "scorefile.txt", }) highestPointsText = score.init({ fontSize = 40, font = "Helvetica", x = \_R - 170, y = \_T + 100, maxDigits = 5, leadingZeros = false, filename = "scorefile.txt", }) --highestPointsText = display.newText("High Score: 0", 0, 0, "Helvetica", 40) --highestPointsText:setFillColor(0) --highestPointsText.x = \_R - 170 --highestPointsText.y = \_T + 100 function onGameOver() Runtime:removeEventListener("touch", touchScreen) Runtime:removeEventListener("collision", onCollision) transition.pause() for i=1,#enemy do if(enemy[i] ~= nil) then display.remove(enemy[i]) end end composer.gotoScene("menu", "fade", 500) composer.removeScene("level1") end local function playerHit() character:setLinearVelocity(0, nil) character.x = \_L + 250 composer.gotoScene("level1-Try-Again") timer.cancel(spawnEnemiesTimer) timer.cancel(moveEnemiesTimer) livesCount = livesCount - 1 if(livesCount \< 1) then onGameOver() end end function onCollision(event) local function removeOnPlayerHit(obj1, obj2) if(obj1 ~= nil and obj1.id == "enemy") then display.remove(obj1) end if(obj2 ~= nil and obj2.id == "enemy") then display.remove(obj2) end if(obj1 ~= nil and obj1.id == "enemy2") then display.remove(obj1) end if(obj2 ~= nil and obj2.id == "enemy2") then display.remove(obj2) end if(obj1 ~= nil and obj1.id == "enemy3") then display.remove(obj1) end if(obj2 ~= nil and obj2.id == "enemy3") then display.remove(obj2) end if(obj1 ~= nil and obj1.id == "enemy4") then display.remove(obj1) end if(obj2 ~= nil and obj2.id == "enemy4") then display.remove(obj2) end end local function showPlayerHit() local tmr\_onPlayerHit = timer.performWithDelay(1, playerHit, 1) end if event.phase == "began" then if((event.object1.id == "enemy" or event.object1.id == "enemy2" or event.object1.id == "enemy3" or event.object1.id == "enemy4") and event.object2.id == "character") then showPlayerHit() removeOnPlayerHit(event.object1, nil) elseif(event.object1.id == "character" and (event.object2.id == "enemy" or event.object2.id == "enemy2" or event.object2.id == "enemy3" or event.object2.id == "enemy4")) then showPlayerHit() removeOnPlayerHit(nil, event.object2) end end end sceneGroup:insert(horizon) sceneGroup:insert(horizon2) sceneGroup:insert(mountainback) sceneGroup:insert(mountainback2) sceneGroup:insert(mountain) sceneGroup:insert(mountain2) sceneGroup:insert(trees) sceneGroup:insert(trees2) sceneGroup:insert(ground) sceneGroup:insert(pointsText) sceneGroup:insert(highestPointsText) sceneGroup:insert(character) sceneGroup:insert(group) sceneGroup:insert(specialGroup) end -- show() function scene:show( event ) local sceneGroup = self.view local phase = event.phase if ( phase == "will" ) then -- Code here runs when the scene is still off screen (but is about to come on screen) local highscore = score.load() score.set(highscore) character.x = \_L + 250 for i=1, livesCount do lives[i].alpha = 0 end for i=1, livesCount do lives[i].alpha = 1 end elseif ( phase == "did" ) then -- Code here runs when the scene is entirely on screen physics.start() horizon.enterFrame = scrollMountains Runtime:addEventListener("enterFrame", horizon) horizon2.enterFrame = scrollMountains Runtime:addEventListener("enterFrame", horizon2) mountainback.enterFrame = scrollMountains Runtime:addEventListener("enterFrame", mountainback) mountainback2.enterFrame = scrollMountains Runtime:addEventListener("enterFrame", mountainback2) mountain.enterFrame = scrollMountains Runtime:addEventListener("enterFrame", mountain) mountain2.enterFrame = scrollMountains Runtime:addEventListener("enterFrame", mountain2) trees.enterFrame = scrollMountains Runtime:addEventListener("enterFrame", trees) trees2.enterFrame = scrollMountains Runtime:addEventListener("enterFrame", trees2) character:play() Runtime:addEventListener("enterFrame", getVelocities) Runtime:addEventListener("touch", touchScreen) Runtime:addEventListener("collision", onCollision) Runtime:addEventListener("enterFrame", highScore) spawnEnemiesTimer = timer.performWithDelay(2500, spawnEnemies, -1) moveEnemiesTimer = timer.performWithDelay(2, moveEnemies, -1) end end -- hide() function scene:hide( event ) local sceneGroup = self.view local phase = event.phase if ( phase == "will" ) then -- Code here runs when the scene is on screen (but is about to go off screen) Runtime:removeEventListener("enterFrame", horizon) Runtime:removeEventListener("enterFrame", horizon2) Runtime:removeEventListener("enterFrame", mountainback) Runtime:removeEventListener("enterFrame", mountainback2) Runtime:removeEventListener("enterFrame", mountain) Runtime:removeEventListener("enterFrame", mountain2) Runtime:removeEventListener("enterFrame", trees) Runtime:removeEventListener("enterFrame", trees2) Runtime:removeEventListener("enterFrame", getVelocities) Runtime:removeEventListener("touch", touchScreen) Runtime:removeEventListener("collision", onCollision) timer.cancel(spawnEnemiesTimer) timer.cancel(moveEnemiesTimer) elseif ( phase == "did" ) then -- Code here runs immediately after the scene goes entirely off screen end end -- destroy() function scene:destroy( event ) local sceneGroup = self.view -- Code here runs prior to the removal of scene's view end -- ----------------------------------------------------------------------------------- -- Scene event function listeners -- ----------------------------------------------------------------------------------- scene:addEventListener( "create", scene ) scene:addEventListener( "show", scene ) scene:addEventListener( "hide", scene ) scene:addEventListener( "destroy", scene ) -- ----------------------------------------------------------------------------------- return scene

Any help or tips would be greatly appreciated.

I apologize for showing the entire code, I do not need a complete rewrite, I just want  tips, suggestions, and/or code snippets.

IF any articles are found relating to this, feel free to send them.

When a problem occur? May be after touch screen? Consider use tap listener instead touch. 

function endJump() character:applyForce(0, 0, self.x, self.y) end

Does it do something useful? 

Edit :

May be you have too many objects in a game?

Are you sure that all event listerners are removed correctly after you removed level1 scene? I not sure that scene:hide metod is invoked. Can you check that?

When it is a tap listener, the player can not jump at all.

Also, Occasionally I get error saying: Attempt to call method applyForce (a nil value).

Does character spirite exist all the time?

Your physic engine is up ad working even level1 scene id off screen? Am I right?

This video shows all three of my current errors. 

One there is lots of lag, two, it goes really quick all of a sudden, and three, it crashes from an error.

https://www.youtube.com/watch?v=rpLGLAlP8Jc

I notice 

(line from playerHit method)

character:setLinearVelocity(0, nil)

but function setLinearVelocity require two numbers. Also changing position of object when physic engine is on is not good idea I think

(line from playerHit method). Why do you not pause physics engine after you leave scene level1? I think it is imporant.

character.x = \_L + 250

In playerHit method after call to gotoScene() I’m  not sure that  rest of code is executed. Check that.

The same thing occurs, it always seems to happen when you choose one character, die, then choose the other and start.

This is the code for the phase == “did”:

elseif ( phase == "did" ) then -- Code here runs immediately after the scene goes entirely off screen physics.pause() end

Try adding print statement in enterframe or collision functions…and when you leave the scene, see your simulator output if it is printing that statements which you have put in your enterframe or collision functions

Problem seems to be related with moving of character. Add print statement and observe console.

function endJump() print("applyForce in endJump") character:applyForce(0, 0, self.x, self.y) end function touchScreen(event) if (event.phase == "began") then if (vy \> -25 and vy \< 25) then print("applyForce in touchScreen") character:applyForce(0, -85, self.x, self.y) timer.performWithDelay(500, endJump, 1) end end end

Little improvments for your code

function spawnEnemies() numOfEnemy = math.random(1, 4) if numOfEnemy == 1 then enemy = display.newSprite(beetle, beetleSequenceData) enemy.x = \_R + 100 enemy.y = \_CY enemy.hasBeenScored = false physics.addBody(enemy, "dynamic", physicsData:get("beetle")) enemy.xScale = -1 enemy.id = "enemy" enemy.isFixedRotation = true enemy:play() group:insert(enemy) elseif numOfEnemy == 2 then enemy2 = display.newSprite(vulture, vultureSequenceData) enemy2.x = \_R + 100 enemy2.y = \_CY - (enemy2.height \* 0.25) enemy2.hasBeenScored = false physics.addBody(enemy2, "dynamic", physicsData:get("vulture")) enemy2.xScale = -1 enemy2.gravityScale = -0.01 enemy2.id = "enemy2" enemy2.isFixedRotation = true enemy2:play() specialGroup:insert(enemy2) elseif numOfEnemy == 3 then enemy3 = display.newSprite(scorpion, scorpionSequenceData) enemy3.x = \_R + 100 enemy3.y = \_CY enemy3.hasBeenScored = false physics.addBody(enemy3, "dynamic", physicsData:get("scorpion")) enemy3.xScale = -1 enemy3.id = "enemy3" enemy3.isFixedRotation = true enemy3:play() group:insert(enemy3) else enemy4 = display.newSprite(bee, beeSequenceData) enemy4.x = \_R + 100 enemy4.y = \_CY - (enemy4.height \* 0.25) enemy4.hasBeenScored = false physics.addBody(enemy4, "dynamic", physicsData:get("bee")) enemy4.xScale = -1 enemy4.gravityScale = -0.01 enemy4.id = "enemy4" enemy4.isFixedRotation = true enemy4:play() specialGroup:insert(enemy4) end end

Instead two call 

removeOnPlayerHit(event.object1, nil) removeOnPlayerHit(nil, event.object2)

you can write one

removeOnPlayerHit(event.object1, nil) removeOnPlayerHit(event.object2, nil)

and remove unneccessary if statements in onCollision function.

Why do you use timer to move enemies instead proper physics function? and how do you move character?

Some helpful article :slight_smile:

https://coronalabs.com/blog/2011/09/14/how-to-spawn-objects-the-right-way/

https://coronalabs.com/blog/2013/02/19/more-physics-tricks-explained/

Wow thank you for all this information I will try it and look into it.

The timer spawns the enemies, not move them, and which if statements are unnecessary?

Also, I have a question relating to this, how would I remove all elements of a display group, I don’t want to remove the display group itself.

There is also an Attempt to getLinearVelocity error as well in line 181 in the getVelocities function

The errors are either in applyForce or getLinearVelocity in the getVelocities(), endJump(), or touchScreen functions. I tried putting if statements to check if character was nil but the errors still occurred.

I have tested the shown and hidden phases when the speed up occurs and the scene:show phase == “did”, where all my event listeners are occurs twice, the crash occurs when scene:hide phase == “will” occurs twice, this is where all event listeners are removed, it tries to remove an EventListener that has already been removed.

Shown = scene:show, phase == “did”

Hidden = scene:hide, phase == “will”

This screenshot shows what was printed in the logs.

https://www.youtube.com/watch?v=str0z-HFb90