Hi all, wonder if you can help me…
I’ve been using Corona for a few months now and loving it…
However, everything I create (3 demo games so far) as soon as I adopt the composer and start using multiple scenes the fps drops over time.
Its obviously something fundamental Im doing wrong.
for example…
I start with main.lua which goes straight to composer.gotoScene(“scene_menu”) - not much going on here - just a button at the moment, so all is well.
the menu takes you to the game, composer.gotoScene(“scene_game”) - you play the game, and the first time you play all is well - it plays at a solid 60 fps.
the player dies - composer.gotoScene(“scene_gameover”) - again not much going on - just a button which takes you back to the start menu.
this is when the trouble starts, if you go through the process again and play the game again - the fps begin to drop each time, next time you play the game runs at 50 fps, next time its around 40 fps, next time its around 20-30 fps. classic memory leak.
I’ve been reading up on lua scope thinking this is surely the issue (being new to lua - its bound to be me just not defining / clearing stuff properly).
I dont use globals (following reading Goodbye Globals - well i do, but i use the method recommended).
I’ve tried declaring all my local variables / functions within the function scene:create( event ) - in the hope it would fully clear them when I remove the scene (using composer.removeScene / composer.recycleOnSceneChange). But the fps still drops.
so im thinking that must be an incorrect method, I’ve now took to forward declaring everything at the start (before function scene:create( event )). Then later i’ve gone through every display object created and using removeSelf() and setting it back to nil (although Im sure you dont have to do this if you if you use sceneGroup:insert ?).
Im now going through and setting every variable created back to nil (just in case), cancelling all the timers - but still no joy.
Basically Im grabbing at straws trying different things - with little joy.
the strange thing is the texture memory is a constant 2.54mb during the game and doesn’t climb and the Memory Usage is between 0.6mb and 1.5mb, it climbs to about 1.5mb then drops to 0.6mb, this happens on each game whether it is 20 fps or 60 fps.
So it seems to be something else.? its got me stumped.
The simulator gives me a solid 60 fps - no matter how many times I play the game.
The test device is a Samsung Tablet.
Im confident its something Im doing wrong / there is something simple Im missing. I will post some of the game code in its current state below.
thanks in advance for any tips…
local composer = require( "composer" ) local scene = composer.newScene() local physics = require( "physics" ) local perspective = require("perspective") local timer2 = require("timer2") local Car = require("Car") local OtherCar = require("OtherCar") local Global = require( "GlobalData" ) physics.start() -- ----------------------------------------------------------------------------------- -- Code outside of the scene event functions below will only be executed ONCE unless -- the scene is removed entirely (not recycled) via "composer.removeScene()"- -- ----------------------------------------------------------------------------------- -- \>\> Forward Declare LOCAL Variables - SEE IF IT STOPS THE FPS DROP! -- \>\> Forward Declare FUNCTIONS. local dt = 1000 / display.fps local last\_ms = 0 math.randomseed(os.time()) local random = math.random -- \>\>\> Make a movable Camera Spot - to track. -- CONSTANT VALUES local \_CX = display.contentWidth\*0.5 local \_CY = display.contentHeight\*0.5 local \_CW = display.contentWidth local \_CH = display.contentHeight local \_T = display.screenOriginY -- Top local \_L = display.screenOriginX -- Left local \_R = display.viewableContentWidth - \_L -- Right local \_B = display.viewableContentHeight - \_T-- Bottom local camera local CameraPoint -- ------------------------------------------------------------------------------- -- \>\>\> Setup Tables local the\_Images = {} local the\_Object = {} local BackgroundEndless = {} local ScrollItemsX = {} local ScrollItemsY = {} local ScrollItemsXdist = {} local ScrollItemsYdist = {} local BackgroundObj1 local distancetravelled = 0 local nextcar local fingametimer local finrect local damagebouncespeed local damagebounce = 0 local displayInfo -- \>\>\> setup GLOBALS Global.backgroundspeed = 3 Global.directionstart = 0 Global.controllerdirection = 0 Global.lastspeed = 0 Global.lastdistance = 0 Global.laneoccupied = {} for j = 1, 7 do Global.laneoccupied[j] = 0 end -- \>\>\> setup TIMERS & transistions local camstarttimer local othercartimer local bouncespeed -- \>\>\> setup FUNCTIONS local on\_enterFrame local generateothercar local onCollision local finishgame local turnoffdamage local fingam -- \>\>\> setup players local player local othercar = {} -- \>\>\> get the graphic filenames local the\_GraphicFileNames = { "freeway.png", "freeway2.png"} -- more GRAPHICS to be added when done hence table. -- \>\>\> load in the images for j = 1, #the\_GraphicFileNames do the\_Images[the\_GraphicFileNames[j]] = { type="image", filename="images/".. the\_GraphicFileNames[j] } -- more GRAPHICS to be added hence table !! end -- functions turnoffbounce = function () bounce = 0 end finishgame = function() fingam = function() Global.GameOver = 1 displayInfo:removeSelf() displayInfo = nil for j = 1, #othercar do othercar[j]:removeSelf() othercar[j] = 0 end othercar = {} othercar = nil player = nil camera:destroy() -- ALWAYS NEEDED TO REMOVE OBJECTS OFF SCREEN. camera = nil Runtime:removeEventListener( "collision", onCollision ) Runtime:removeEventListener( "enterFrame", on\_enterFrame ) onCollision = nil on\_enterFrame = nil display.remove(displayInfo) displayInfo = nil timer.cancel(fingametimer) timer.cancel(camstarttimer) timer.cancel(othercartimer) timer.cancel(bouncespeed) camstarttimer = nil othercartimer = nil bouncespeed = nil fingametimer = nil display.getCurrentStage():setFocus( nil ) composer.gotoScene("scene-gameover") end fingametimer = timer.performWithDelay(2000, fingam) end -- "scene:create()" function scene:create( event ) local sceneGroup = self.view -- Initialize the scene here -- Example: add display objects to "sceneGroup", add touch listeners, etc. -- \>\>\> Build Camera camera = perspective.createView() camera:setBounds(display.contentCenterX, display.contentCenterX\*1.44,false, false) -- Lock X axis to screen limits camera:toPoint(128, 284) -- Change the cameras focus to an X,Y point CameraPoint = display.newRect( 128, 284, 10, 10 ) CameraPoint:setFillColor( 255,0,0 ) CameraPoint.alpha = 0 CameraPoint.x = \_CX CameraPoint.y = \_CH camera:add(CameraPoint, 1) camera:setMasterOffset((\_CW-256)\*0.5, 150) camera.damping = 1 -- A bit more fluid tracking camera:setFocus(CameraPoint) -- Set the focus to the player camera:track() camstarttimer = timer.performWithDelay( 1000, function() camera.damping = 20; end, 1 , "TimerRunning", false ) -- \>\>\> setup newRects in scene in the correct location -- Endless Background Object 18 BackgroundObj1 = display.newRect(0,0,312,515) -- make slightly over in height to avoid black lines BackgroundObj1.fill = the\_Images["freeway.png"] BackgroundObj1.anchorX = 0 BackgroundObj1.anchorY = 0 BackgroundEndless[#BackgroundEndless+1] = BackgroundObj1 -- more backgrounds to be added hence table !! sceneGroup:insert( BackgroundObj1 ) camera:add(BackgroundObj1 , 3) -- add to camera level for j = 1, #the\_GraphicFileNames do the\_Images[the\_GraphicFileNames[j]] = nil end displayInfo = display.newText("Speed: - MPH" , \_CX, 20, native.systemFontBold, 12) displayInfo:toFront( ) -- \>\>\> Add Camera to Player camera:prependLayer() -- \>\>\> Set the Parallax Settings camera:setParallax(1, 0.9, 0.8, 0.7, 0.6, 0.5, 0.4, 0.3) -- Here we set parallax for each layer in descending order CameraPoint:toFront( ) player = Car:new() player.damage = 0 player.x = CameraPoint.x - (player.width \* 0.25) player.y = CameraPoint.y sceneGroup:insert(player) camera:add(player,2) generateothercar = function () local lanefullcount = 0 for j = 1, 6 do if Global.laneoccupied[j] == 1 then lanefullcount = lanefullcount + 1 end end if lanefullcount == 6 then return end -- all lanes full nextcar = #othercar othercar[nextcar] = OtherCar:new() othercar[nextcar]:start(true) sceneGroup:insert(othercar[nextcar]) camera:add(othercar[nextcar],2) camera:add(othercar[nextcar].num,2) camera:add(othercar[nextcar].num2,2) end othercartimer = timer.performWithDelay(2500, generateothercar, -1) onCollision = function (event) if event.object1.id == "player" and event.object2.id == "powerup" then Global.backgroundspeed = Global.backgroundspeed + 0.05 if bounce == 0 then bouncespeed = transition.to( displayInfo, { time=100, xScale=1.3, yScale=1.3 } ); transition.to( displayInfo, { time=100, delay = 100, xScale=1, yScale=1, onComplete=turnoffbounce} ); bounce = 1; end end if event.object1.id == "powerup" and event.object2.id == "player" then Global.backgroundspeed = Global.backgroundspeed + 0.05 end if event.object1.id == "player" and event.object2.id == "othercar" then player.damage = player.damage + random(10,30) if player.damage \>= 100 then player.damage = 100 end if player.y \> 530 then player.damage = 100 end Global.backgroundspeed = Global.backgroundspeed - 0.5 if Global.backgroundspeed \< 2.5 then Global.backgroundspeed = 2.5 end if player.damage \>= 100 then finishgame() end end if event.object1.id == "othercar" and event.object2.id == "player" then player.damage = player.damage + random(10,30) if player.damage \>= 100 then player.damage = 100 end if player.y \> 530 then player.damage = 100 end Global.backgroundspeed = Global.backgroundspeed - 0.5 if Global.backgroundspeed \< 2.5 then Global.backgroundspeed = 2.5 end if player.damage \>= 100 then finishgame() end end end Runtime:addEventListener( "collision", onCollision ) -- \>\>\> Set the Endless Background Update and Checks on\_enterFrame = function ( event ) if player.y \> 455 and Global.backgroundspeed \> 3 then player.y = player.y -1 end distancetravelled = distancetravelled + (((((Global.backgroundspeed\* 20)\*0.01666)\*0.01666)\*0.01666)) if Global.backgroundspeed \* 20 \> Global.hispeed then Global.hispeed = Global.backgroundspeed \* 20 end if distancetravelled \> Global.lastdistance then Global.lastdistance = distancetravelled end if Global.backgroundspeed \* 20 \> Global.lastspeed then Global.lastspeed = Global.backgroundspeed \* 20 end if distancetravelled \> Global.bestdistance then Global.bestdistance = distancetravelled end BackgroundObj1.y = BackgroundObj1.y+Global.backgroundspeed BackgroundObj1.contentX, BackgroundObj1.contentY = BackgroundObj1:localToContent(0, 0) BackgroundObj1.Pbuffer = BackgroundObj1.height \* 0.05 BackgroundObj1.P = BackgroundObj1.height \* 0.5 BackgroundObj1.P = BackgroundObj1.P + BackgroundObj1.Pbuffer if BackgroundObj1.contentY \< 0 - BackgroundObj1.P then BackgroundObj1:translate(0, 512) end --move to new position. if displayInfo ~= nil then displayInfo.text = string.format("Speed: %.1f MPH", Global.backgroundspeed \* 20) displayInfo:toFront() end -- check and update scrolling backgrounds if Global.backgroundspeed \> 4 then Global.backgroundspeed = Global.backgroundspeed - 0.0001 end CameraPoint.x = player.x player:toFront( ) -- check scrolling items for i = 1, #ScrollItemsX do ScrollItemsX[i]:translate(ScrollItemsXdist[i], 0) end for i = 1, #ScrollItemsY do ScrollItemsY[i]:translate(0,ScrollItemsYdist[i]) end if Global.controllerdirection == 1 then player.x = player.x - 3 end if Global.controllerdirection == 2 then player.x = player.x + 3 end if player.x \> 288 then player.x = 288 end if player.x \< 8 then player.x = 8 end end Runtime:addEventListener( "enterFrame", on\_enterFrame ) end -- \*\*\* DO NOT DELETE !!!!! \*\*\*\* ... "scene:create()" \*\*\*\* 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. -- \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* -- GAME CODE HERE ! -- \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* -- This will remove the game scene when available. This is important to allow the game scene to reset itself. local prevScene = composer.getSceneName( "previous" ) if(prevScene) then composer.removeScene( prevScene ) end end -- \*\*\* DO NOT DELETE !!!!! \*\*\*\* ... "scene:show() - will / did " \*\*\*\* END \*\*\*\* end -- \*\*\* DO NOT DELETE !!!!! \*\*\*\* ... "scene:show()" \*\*\*\* 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, etc. elseif ( phase == "did" ) then -- Called immediately after scene goes off screen end -- \*\*\* DO NOT DELETE !!!!! \*\*\*\* ... "scene:hide() - will / did " \*\*\*\* END \*\*\*\* end -- \*\*\* DO NOT DELETE !!!!! \*\*\*\* ... "scene:hide()" \*\*\*\* END \*\*\*\* -- "scene:destroy() function scene:destroy( event ) local sceneGroup = self.view -- \*\*\* JUST ADDED THE BELOW !!! TO TRY AND SEE IF THIS STOPS FPS DROP !! dt = nil last\_ms = nil random = nil camera = nil CameraPoint = nil -- \>\>\> Setup Tables the\_Images = nil the\_Object = nil BackgroundEndless = nil ScrollItemsX = nil ScrollItemsY = nil ScrollItemsXdist = nil ScrollItemsYdist = nil distancetravelled = nil nextcar = nil fingametimer = nil finrect = nil damagebouncespeed = nil damagebounce = nil -- \>\>\> reset GLOBALS Global.backgroundspeed = 3 Global.directionstart = 0 Global.controllerdirection = 0 Global.lastspeed = 0 Global.lastdistance = 0 Global.laneoccupied = nil -- \>\>\> setup TIMERS & transistions camstarttimer = nil othercartimer = nil bouncespeed = nil -- \>\>\> setup FUNCTIONS on\_enterFrame = nil generateothercar = nil onCollision = nil finishgame = nil turnoffdamage = nil fingam = nil -- \>\>\> setup players player = nil othercar = nil -- \>\>\> get the graphic filenames the\_GraphicFileNames = nil -- Called prior to the removal of scenes view -- Insert code here to clean up the scene -- Example: remove display objects, save state, etc. end -- \*\*\* DO NOT DELETE !!!!! \*\*\*\* ... "scene:destroy()" \*\*\*\* END \*\*\*\* -- ------------------------------------------------------------------------------- -- Listener setup scene:addEventListener( "create", scene ) scene:addEventListener( "show", scene ) scene:addEventListener( "hide", scene ) scene:addEventListener( "destroy", scene ) -- ------------------------------------------------------------------------------- return scene