Hello there!
I will elaborate further what I mean with this problem, we have made different theories of what the caused the lag but none of it worked.
First thing to know (functions):
spawnMobs() = A function that creates mobs every 500ms.
----- Spawn small sized ships local function spawnMobs() if pause then return; end ----- By the word itself if(gameStatus ~= "started") then return; end local mob = display.newSprite( mobImageSheet , mobSequenceData) mob:setSequence("idle") mob:play() mob.xScale = 0.9 ----- start Location mob.x = startLoc.x mob.y = startLoc.y ----- of course mob.type = "mob" ----- Where should I go? mob.column = waypointCounter ----- Row Index mob.rowIndex = 0 ----- I am the smaller one mob.midsize = false ----- Column Index mob.colIndex = 0 ----- Points of the mob if killed mob.points = 10 ----- Self Destruct? mob.selfDestruct = false ----- 200 - 1 = 199! more spawnRemaining = spawnRemaining - 1 updateSpawn() ----- Im hit? mob.isHit = false ----- Transition Handler ----- So I can pause this mob.transition = nil ----- Dont rotate if something bad happen mob.isFixedRotation = true ----- This is used to resume a paused transition (actually it is cancelled) ----- To create a new transition after the game is paused with a reduced time mob.baseTime = 0 ----- Mob status mob.status = "porting" ----- Add to physics world physics.addBody(mob, "dynamic", {isSensor = true, radius = 10}) ----- Go to start waypoint mob.transition = transition.to(mob, {y = startWaypoint.y, time = startWaypoint.baseTime}) mob.baseTime = startWaypoint.baseTime ----- So we will know where this ship is heading after resumed from pause state mob.headingx = nil mob.headingy = startWaypoint.y ----- Ship ID mob.id = #mobs + 1 ----- Insert to ship object group objects:insert(mob) table.insert(mobs, mob) mothership:toFront() ----- Next spawn should go to the next column startWaypoint.nextWaypoint() ----- Wait spawnDelay ms to spawn another hone triggerSpawn() playSound(shipSpawnSound) end
spawnMidSizeMob() = A function that creates a unique mob every 10000ms. *This one resolves the lag state*
----- Spawn MidSized Ships local function spawnMidSizeMob() midsize = display.newSprite( midImageSheet , midSequenceData) midsize:setSequence("teleport") midsize:play() ----- Where will I spawn? Left | Middle | Right local counter = math.random(0,2) ----- LEFT if counter == 0 then midsize.x = gate1.x ----- MIDDLE elseif counter == 1 then midsize.x = gate2.x ----- Right else midsize.x = gate3.x end ----- Y Coordinate midsize.y = (gate1.y + gate1.height / 2) + (midsize.height / 2) ----- I am an enemy ship midsize.type = "mob" ----- Im Hit! midsize.isHit = false ----- Teleporting midsize.status = "spawn" ----- This ship is not docked midsize.rowIndex = 0 midsize.colIndex = 0 midsize.midsize = true ----- Teleport Delay midsize.delay = 30 ----- Move after teleport delay midsize.elapsed = 0 ----- Points given by this mob is 100 \* multiplier| (Points = Chance) ----- 400 = 10% | 300 = 10% | 200 = 10% | 100 = 90% of 100 local multiplier if math.random(1,100) \<= 90 then multiplier = 1 else local chance = math.random(1,3) if chance == 1 then multiplier = 2 elseif chance == 2 then multiplier = 3 elseif chance == 3 then multiplier = 4 end end midsize.points = 100 \* multiplier ----- Add to physics world physics.addBody(midsize, "dynamic", {isSensor = true, radius = 16}) objects:insert(midsize) playSound(lauchShipSound) ----- Trigger next Mid Size ship spawn triggerMidSpawn() end
pause and resume
----- Inside Pause Function physics.pause() cancelAllTransitions() ----- Resume from paused state local function resume() gameStatus = fromStatus resumeAllTransitions() physics.start(true) if tickTimer ~= nil then timer.resume(tickTimer); end if mobText ~= nil then mobText.alpha = 1; end if nextLevelText ~= nil then nextLevelText.alpha = 1; end end
cancellAllTransition() = A function that works like pause button. (Cancels all possible transitions on screen)
----- Cancel Transitions ----- Stop moving everything ----- No animations local function cancelAllTransitions() if gameStatus == "starting" or gameStatus == "leave" then transition.cancel(mothership.transition) mothership:pause() elseif (gameStatus == "started" or gameStatus == "playerdead") then mothership:pause() if spawnTimer ~= nil then timer.pause(spawnTimer); end if midShipSpawnTimer ~= nil then timer.pause(midShipSpawnTimer); end for i = #explosions, 1, -1 do if explosions[i] ~= nil then explosions[i]:pause() end end if move ~= nil then timer.cancel(move) end for i = 1, #mobs do if mobs[i] ~= nil then if mobs[i].transition ~= nil then transition.cancel(mobs[i].transition) mobs[i]:pause() end end end for i = 1, #shots do if shots[i] ~= nil then if shots[i].transition ~= nil then transition.cancel(shots[i].transition) end end end if midsize ~= nil then if midsize.status == "active" then transition.cancel(midsize.transition) midsize:pause() end end end end
resumeAllTransitions() = A function that works like resume button. (Creates multiple transition instance of all objects that possibly move on screen)
----- Resume Transitions function resumeAllTransitions() if gameStatus == "starting" then mothership:play() mothership.transition = transition.to(mothership, {x = display.contentWidth / 2, time = mothership.baseTime, onComplete = function() startSpawn = true end}) elseif gameStatus == "leave" then mothership.transition = transition.to(mothership, {x = display.viewableContentWidth + mothership.width / 2, time = mothership.baseTime, onComplete = function() mothership.baseTime = 3000 gameStatus = "starting" playSound(mothershipSound) mothership.transition = transition.to(mothership, {x = display.contentWidth / 2, time = mothership.baseTime, onComplete = function() startSpawn = true end}) end}) elseif (gameStatus == "started" or gameStatus == "playerdead") then mothership:play() if spawnTimer == nil then triggerSpawn() else timer.resume(spawnTimer) end if midShipSpawnTimer == nil then triggerMidSpawn() else timer.resume(midShipSpawnTimer) end for i = 1, #mobs do if mobs[i] ~= nil then if not mobs[i].selfDestruct then if gameStatus ~= "playerdead" then if mobs[i].headingx == nil then mobs[i].transition = transition.to(mobs[i], {y = mobs[i].headingy, time = mobs[i].baseTime}) elseif mobs[i].headingy == nil then mobs[i].transition = transition.to(mobs[i], {x = mobs[i].headingx, time = mobs[i].baseTime}) end end mobs[i]:play() end end end for i = 1, #explosions do if explosions[i] ~= nil then explosions[i]:play() end end if gameStatus ~= "playerdead" then for i = 1, #shots do if shots[i] ~= nil then if not shots[i].miss then shots[i].transition = transition.to(shots[i], {y = 0, time = shots[i].baseTime}) end end end if midsize ~= nil then if not midsize.selfDestruct then if midsize.status == "active" then midsize.transition = transition.to(midsize, {y = floor.y, time = midsize.baseTime}) end midsize:play() end end end end end
exitScene() = The way I remove objects when game screen is terminated *Pressed return to main menu from pause scene or game over scene*. Game Over and Pause Scene over storyboard overlays.
function scene:exitScene(event) local view = self.view leave = false gate1:removeSelf() gate1 = nil gate2:removeSelf() gate2 = nil gate3:removeSelf() gate3 = nil scoreText:removeSelf() scoreText = nil waveText:removeSelf() waveText = nil if nextLevelText ~= nil then nextLevelText:removeSelf() nextLevelText = nil end stopSounds() if player ~= nil then Runtime:removeEventListener("tap", player.shoot) Runtime:removeEventListener("touch", touchDrag) player:removeSelf() player = nil laserPointer:removeSelf() laserPointer = nil end mothership:removeSelf() mothership = nil rateGameTrap = false Runtime:removeEventListener("enterFrame", main) Runtime:removeEventListener("collision", onCollision) if ( fromStatus == "started" or gameStatus == "gameover" ) then for i = #mobs, 1, -1 do if mobs[i] ~= nil then mobs[i]:removeSelf() mobs[i] = nil end end mobs = {} for i = #explosions, 1, -1 do if explosions[i] ~= nil then explosions[i]:removeSelf() explosions[i] = nil end end explosions = {} if midsize ~= nil then midsize:removeSelf() midsize = nil end for i = #shots, 1, -1 do if shots[i] ~= nil then shots[i]:removeSelf() shots[i] = nil end end shots = {} for row = 1, 4 do for col = 1, 10 do docks[row][col].docked = 0 docks[row][col].isFilled = false docks[row][col]:removeSelf() docks[row][col] = nil end end docks = {} for row = topWaypoints.numChildren, 1, -1 do topWaypoints[row]:removeSelf() topWaypoints[row] = nil end topWaypoints = {} startWaypoint:removeSelf() startWaypoint = nil end for i = #terrain, 1, -1 do terrain[i]:removeSelf() terrain[i] = nil table.remove(terrain, i) end if tickTimer ~= nil then timer.cancel(tickTimer); end end
tickTimer = A forever timer that executes every 1690ms and plays a background sound effect.
------ This code is executed once... tickTimer = timer.performWithDelay(1690, function() if gameStatus == "started" then playSound(spawnCountSound) end end, -1)
player = Player ship
storyboard = Scene Management
Now here’s the thing, the lag happens when user:
play the game from main menu > get a game over > return to main menu > click new game > play the game as long as possible > at any level start *This only occur once!* The game LAGS!.
This is how next level works, when this level is finished/cleared the game will pause for a while using pause() and after a while starts level 2 and calls resume() and then if LUCKY the game will lag for a moment.
What is game LAGS?
Based on what I have analyzed on what is happening in code. My greatest bet was code execution stopped until timer fire was released *The spawnMidSizeMob() at the top, It was controlled by a timer.performWithDelay(10000, spawnMidSizeMob(), -1)*. The lag disappears and resumes to its normal state when this timer fired.
Here’s another thing, what happened during that lag? If you remember that spawnMob() function that executes every 500ms did not function anymore + that tickTimer that plays a sound effect every 1690ms did not play anymore + player ship cannot move no matter how you touch drag your phone screen, but except for spawnMidSize timer since it is 10000ms this was executed before the lag happened and this saved the day when it is fired *everything resumes like there’s nothing happened*.
Now here’s our theories that may cause the lag, I did manage to make a fix but the lag still appear.
->storyboard scene *This lag only happen when you exit to main menu and play again*
->very high process usage *I noticed there are lag spikes happening in game, jitter and freeze effects for milliseconds*
->memory leak? *I checked memory and texture usage and no leaks at all*
->exitScene -> removed objects in a wrong way? *I think it’s good*
->Unknown reason.
Sorry for the long post XD. Just ask me if something is confusing, I am having a hard time with this lag and I want to get rid of it but I think I can’t do it alone anymore. The issue is pretty hard.
Thanks in advance.