Levels keep slowing down (director + Particle Candy)

Hello!

Maybe someone can help me a bit and give some pointers.
The problem is that my game levels keep slowing (dropping objects get slower and slower, no crashes though) down on device every time I restart them or even choose another one.

Have struggled with it for over a week now and tried a lot of different solutions what I can figure out but clearly there is some issue with my code.

The basic set up is

main.lua > loadmainmenu.lua > loadlevels.lua > loadlevel.lua > levelX.lua

I´m using director 1.4
Particle Candy 1.0.26
Corona Build 2012.971 (tried also older public ones - same issue)
building for iOS

This level is quite stripped down now, removed visual effects like floating score numbers, catching animations etc.

[lua]local level4 = {}

– Main function - MUST return a display.newGroup()
level4.new = function( params )

local localGroup = display.newGroup()
local sprite = require “sprite”
local physics = require “physics”
local ui = require “ui”
local Particles = require(“lib_particle_candy”)

local screenW = display.contentWidth
local screenH = display.contentHeight

physics.start()
physics.setGravity (0,0)

local background
local menuBtn
local counter
local timerInfo
local numSeconds = 10
local gamePoints = 0
local pointsText
local scoreText
local highScoreText
local shade
local gameOverScreen
local gameIsActive = false
local gameScore = 0
local highScore
local Enemy
local sheTouch = “”
local she3Touch = “”
local she4Touch = “”

– sounds
local backgroundSound = audio.loadSound(“sounds/L2BI.mp3”)
local backgroundSoundA = audio.loadSound(“sounds/L2BIamb.mp3”)
local gameOverSound = audio.loadSound( “sounds/gameover.wav” )
local btnSound = audio.loadSound( “sounds/btnSound.wav” )

–Get the current unlocked level value
currentLevel = loadFile(“currentLevel.txt”)
print “Level 4”

– saveValue() --> used for saving high score, etc.

–***************************************************
local saveValue = function( strFilename, strValue )
– will save specified value to specified file
local theFile = strFilename
local theValue = strValue

local path = system.pathForFile( theFile, system.DocumentsDirectory )

– io.open opens a file at path. returns nil if no file found
local file = io.open( path, “w+” )
if file then
– write game score to the text file
file:write( theValue )
io.close( file )
end
end

–***************************************************

– loadValue() --> load saved value from file (returns loaded value as string)

–***************************************************
local loadValue = function( strFilename )
– will load specified file, or create new file if it doesn’t exist

local theFile = strFilename

local path = system.pathForFile( theFile, system.DocumentsDirectory )

– io.open opens a file at path. returns nil if no file found
local file = io.open( path, “r” )
if file then
– read all contents of file into a string
local contents = file:read( “*a” )
io.close( file )
return contents
else
– create file b/c it doesn’t exist yet
file = io.open( path, “w” )
file:write( “0” )
io.close( file )
return “0”
end
end

local gameActivate = function()

gameIsActive = true
mainMusic = audio.play( backgroundSound, { loops=-1 } )
mainAmbient = audio.play( backgroundSoundA, { loops=-1, volume=0.5 } )

end

– SCORE MODULE
local setScore = function( scoreNum )

local newScore = scoreNum
gameScore = newScore

if gameScore < 0 then gameScore = 0; end

scoreText.text = "Love: " … tostring( gameScore )
scoreText.xScale = 0.5; scoreText.yScale = 0.5
scoreText.x = 40
scoreText.y = 15

if gameScore >= 5 then
transition.to( infoText, { time=2000, alpha=0, y = 0} )
transition.to( levelText, { time=2000, alpha=0, y = -20 } )
end

if gameScore == 50 then
transition.to ( levelAlmost, {time=3000, alpha=1})
elseif gameScore >= 55 then
transition.to ( levelAlmost, {time=3000, alpha=0})
end

if gameScore == 80 then
levelAbit.alpha = 1
elseif gameScore >= 85 then
levelAbit.alpha = 0
end

end

local setPoints = function( pointsNum )

local newPoints = pointsNum
gamePoints = newPoints

if gamePoints < 0 then gamePoints = 0; end
pointsText.text = "Luck: " … tostring( gamePoints )
pointsText.xScale = 0.5; pointsText.yScale = 0.5
pointsText.x = 40
pointsText.y = 35
end

–***************************************************
– CALL GAMEOVER OR VICTORY
–***************************************************
local callGameOver = function()

audio.stop(mainMusic)
audio.dispose(backgroundSound)
mainMusic = nil
backgroundSound = nil

audio.stop(mainAmbient)
audio.dispose(backgroundSoundA)
mainAmbient = nil
backgroundSoundA = nil
gameIsActive = false
physics.stop()

Runtime:removeEventListener( “collision”, onCollision )
Runtime:removeEventListener( “enterFrame”, main )
E1 = nil
E2 = nil
E3 = nil
E4 = nil
E5 = nil
Particles.CleanUp()

if gameScore >= 99 then
shade = display.newRect( 0, 0, 480, 320 )
shade:setFillColor( 0, 0, 0, 255 )
shade.x = 240; shade.y = 160
shade.alpha = 0
victoryScreen = display.newImageRect( “images/victoryScreen.png”, 480, 320 )
victoryScreen.x = 240; victoryScreen.y = 160
victoryScreen.alpha = 0
localGroup:insert( shade )
localGroup:insert( victoryScreen )

if tonumber(currentLevel) < 5 then
saveFile(“currentLevel.txt”, 5)
end

local onNextTouch = function( event )
if event.phase == “release” then

audio.play( buttonSound )
local numSeconds = 10
local gamePoints = 0
local gameIsActive = false
local gameScore = 0
local sheTouch = “”
local she3Touch = “”
local she4Touch = “”
function clean ( event )
Particles.CleanUp()
end
director:changeScene( “levels” )

end
end

nextBtn = ui.newButton{
defaultSrc = “images/nextbtn.png”,
defaultX = 84,
defaultY = 34,
overSrc = “images/nextbtn-over.png”,
overX = 84,
overY = 34,
onEvent = onNextTouch,
id = “LevelButton”,
text = “”,
font = “Helvetica”,
textColor = { 255, 255, 255, 255 },
size = 16,
emboss = false
}

nextBtn.x = 430; nextBtn.y = 300
localGroup:insert( nextBtn )

else
audio.play( gameOverSound )
shade = display.newRect( 0, 0, 480, 320 )
shade:setFillColor( 0, 0, 0, 255 )
shade.x = 240; shade.y = 160
shade.alpha = 0
gameOverScreen = display.newImageRect( “images/gameOver.png”, 480, 320 )
gameOverScreen.x = 240; gameOverScreen.y = 160
gameOverScreen.alpha = 0
localGroup:insert( shade )
localGroup:insert( gameOverScreen )

local onRestartTouch = function( event )

if event.phase == “release” then
audio.play( buttonSound )
local numSeconds = 10
local gamePoints = 0
local gameIsActive = false
local gameScore = 0
local sheTouch = “”
local she3Touch = “”
local she4Touch = “”
function clean ( event )
Particles.CleanUp()
end
director:changeScene( “load” )
end
end

restBtn = ui.newButton{
defaultSrc = “images/restartbtn.png”,
defaultX = 84,
defaultY = 34,
overSrc = “images/restartbtn-over.png”,
overX = 84,
overY = 34,
onEvent = onRestartTouch,
id = “RestartButton”,
text = “”,
font = “Helvetica”,
textColor = { 255, 255, 255, 255 },
size = 16,
emboss = false
}

restBtn.x = 440; restBtn.y = 305
localGroup:insert( restBtn )
end

local newScore = gameScore
setScore( newScore )
–TRANSITION VICTORY ASSETS
transition.to( shade, { time=200, alpha=0.65 } )
transition.to( victoryScreen, { time=500, alpha=1 } )
–TRANSITION GAME OVER ASSETS
transition.to( shade, { time=200, alpha=0.65 } )
transition.to( gameOverScreen, { time=500, alpha=1 } )

scoreText.isVisible = false
scoreText.text = "Last Love: " … tostring( gameScore )
scoreText:setTextColor( 255, 255, 255 )
scoreText.xScale = 0.5; scoreText.yScale = 0.5 --> for clear retina display text
scoreText.x = 240
scoreText.y = 185
scoreText:toFront()
timer.performWithDelay( 0, function() scoreText.isVisible = true; end, 1 )

– Compare scores
if gameScore > highScore then
highScore = gameScore
local highScoreFilename = “highScore4.data”
saveValue( highScoreFilename, tostring(highScore) )
end

– SHOW HIGH SCORE
highScoreText = display.newText( "Deepest Love: " … tostring( highScore ), 0, 0, “Buxton Sketch”, 30 )
highScoreText:setTextColor( 255, 255, 255 )
highScoreText.xScale = 0.5; highScoreText.yScale = 0.5
highScoreText.x = 240
highScoreText.y = 204

localGroup:insert( highScoreText )

local onMenuTouch = function( event )
if event.phase == “release” then
audio.play( buttonSound )
local numSeconds = 10
local gamePoints = 0
local gameIsActive = false
local gameScore = 0
local sheTouch = “”
local she3Touch = “”
local she4Touch = “”
function clean ( event )
Particles.CleanUp()
end

director:changeScene( “mainmenu” )
end
end

menuBtn = ui.newButton{
defaultSrc = “images/menubtn.png”,
defaultX = 75,
defaultY = 30,
overSrc = “images/menubtn-over.png”,
overX = 75,
overY = 30,
onEvent = onMenuTouch,
id = “MenuButton”,
text = “”,
font = “Helvetica”,
textColor = { 255, 255, 255, 255 },
size = 16,
emboss = false
}

menuBtn.x = 40; menuBtn.y = 300
localGroup:insert( menuBtn )
end
local background = display.newImageRect( “images/bg2.png”, 480, 320 )
background.x = 240; background.y = 160
localGroup:insert( background )
–***************************************************
– GAME TIMER
–***************************************************
local myTimer = function()
numSeconds = numSeconds - 1
counter.text = "Left: " … tostring( numSeconds )
print( numSeconds )

if numSeconds < 1 then
timer.cancel( timerInfo )
restartTimer = timer.performWithDelay( 300, function() callGameOver(); end, 1 )
end
end

local startTimer = function()
print( “Start Timer” )
timerInfo = timer.performWithDelay( 1000, myTimer, 0 )
end

–***************************************************
– HUD
–***************************************************
local hud = function()

counter = display.newText( "Left: " … tostring( numSeconds ), 0, 0, “Buxton Sketch”, 44 )
counter:setTextColor( 0, 0, 0 )
counter.xScale = 0.5; counter.yScale = 0.5
counter.x = 430
counter.y = 15

localGroup:insert( counter )

scoreText = display.newText( "Love: " … tostring( gameScore ), 0, 0, “Buxton Sketch”, 44 )
scoreText:setTextColor( 0, 0, 0 )
scoreText.xScale = 0.5; scoreText.yScale = 0.5
scoreText.x = 40
scoreText.y = 15

localGroup:insert( scoreText )

pointsText = display.newText( "Luck: " … tostring( gamePoints ), 0, 0, “Buxton Sketch”, 44 )
pointsText:setTextColor( 0, 0, 0 )
pointsText.xScale = 0.5; pointsText.yScale = 0.5
pointsText.x = 40
pointsText.y = 35

localGroup:insert( pointsText )

levelAlmost = display.newText( “Almost there…”, 0, 0, “Buxton Sketch”, 70 )
levelAlmost:setTextColor( 0, 0, 0 )
levelAlmost.xScale = 0.5; levelAlmost.yScale = 0.5
levelAlmost.x = screenW/2
levelAlmost.y = 100
levelAlmost.alpha = 0;
localGroup:insert( levelAlmost )

levelAbit = display.newText( “A bit more…”, 0, 0, “Buxton Sketch”, 70 )
levelAbit:setTextColor( 0, 0, 0 )
levelAbit.xScale = 0.5; levelAbit.yScale = 0.5
levelAbit.x = screenW/2
levelAbit.y = 100
levelAbit.alpha = 0;
localGroup:insert( levelAbit )
levelText = display.newText( “Beginning 4: The Contact”, 0, 0, “Buxton Sketch”, 36 )
levelText:setTextColor( 0,0,0 )
levelText.xScale = 0.5; levelText.yScale = 0.5
levelText.x = screenW/2
levelText.y = 17

localGroup:insert( levelText )
infoText = display.newText( “Tilt your world (avoid the empty looks)”, 0, 0, “Buxton Sketch”, 28 )
infoText:setTextColor( 0,0,0 )
infoText.xScale = 0.5; infoText.yScale = 0.5
infoText.x = screenW/2
infoText.y = 40
localGroup:insert( infoText )

return hud

end

– MAKE FX FIELDS DRAGGABLE
local startDrag = function( event )
local Field = event.target
local phase = event.phase
if “began” == phase then
display.getCurrentStage():setFocus( Field )
Field.isFocus = true
– STORE INITIAL POSITION
Field.x0 = event.x - Field.x
Field.y0 = event.y - Field.y
elseif Field.isFocus then
if “moved” == phase then
Field.x = event.x - Field.x0
Field.y = event.y - Field.y0
elseif “ended” == phase or “cancelled” == phase then
display.getCurrentStage():setFocus( nil )
Field.isFocus = false
end
end

return true
end

– ENEMY
local Enemy = display.newImageRect(“images/paddle.png”, 67, 63)
Enemy.x = screenW* .5
Enemy.y = screenH*.1
Enemy.rotation = 180
Enemy.name = “ENEMY”
physics.addBody( Enemy, “dynamic”, { radius = 32 } )
Enemy:addEventListener( “touch”, startDrag )

localGroup:insert( Enemy )

Particles.CreateEmitter(“E1”, screenW*0.1, screenH*0.99, 0, false, true)
–local Properties = {}
Particles.CreateParticleType (“Shots”,
{
imagePath = “images/eye2.png”,
imageWidth = 77,
imageHeight = 32,
velocityStart = 150,
– velocityVariation = 100,
autoOrientation = false,
killOutsideScreen = true,
lifeTime = 10000,
alphaStart = 1.00,
rotationVariation = 360,
emissionShape = 1,
emissionRadius = 450,

PhysicsMaterial = { density = 0, friction = 0, bounce = 0 },
PhysicsProperties = { isFixedRotation = true, isSleepingAllowed = true, bodyType = “kinematic”, isSensor = true, name = “SHOT” }
} )

Particles.AttachParticleType(“E1”, “Shots”, 0.5, 99999,0)

local Emitter1 = Particles.GetEmitter(“E1”)
localGroup:insert(Emitter1)
–gameGroup:insert(Particles.GetEmitter(“E1”))
Particles.StartEmitter(“E1”)
Particles.CreateEmitter(“E2”, screenW*0.1, screenH*0.99, 0, false, true)
–local Properties = {}
Particles.CreateParticleType (“Shots2”,
{
imagePath = “images/eye3.png”,
imageWidth = 79,
imageHeight = 34,
velocityStart = 150,
– velocityVariation = 200,
autoOrientation = false,
killOutsideScreen = true,
lifeTime = 10000,
alphaStart = 1.00,
rotationVariation = 360,
emissionShape = 1,
emissionRadius = 450,

PhysicsMaterial = { density = 0, friction = 0, bounce = 0 },
PhysicsProperties = { isFixedRotation = true, isSleepingAllowed = true, bodyType = “kinematic”, isSensor = true, name = “SHOT2” }
} )
Particles.AttachParticleType(“E2”, “Shots2”, 0.5, 99999,0)

local Emitter2 = Particles.GetEmitter(“E2”)
localGroup:insert(Emitter2)
–gameGroup:insert(Particles.GetEmitter(“E2”))
Particles.StartEmitter(“E2”)
Particles.CreateEmitter(“E3”, screenW*0.1, screenH*0.99, 0, false, true)
–local Properties = {}
Particles.CreateParticleType (“Shots3”,
{
imagePath = “images/eye4.png”,
imageWidth = 67,
imageHeight = 37,
velocityStart = 150,
– velocityVariation = 200,
autoOrientation = false,
killOutsideScreen = true,
lifeTime = 10000,
alphaStart = 1.00,
rotationVariation = 360,
emissionShape = 1,
emissionRadius = 450,

– APPLY PHYSICS:
PhysicsMaterial = { density = 0, friction = 0, bounce = 0 },
PhysicsProperties = { isFixedRotation = true, isSleepingAllowed = true, bodyType = “kinematic”, isSensor = true, name = “SHOT3” }
} )

Particles.AttachParticleType(“E3”, “Shots3”, 0.5, 99999,0)

local Emitter3 = Particles.GetEmitter(“E3”)
localGroup:insert(Emitter3)
–gameGroup:insert(Particles.GetEmitter(“E3”))
Particles.StartEmitter(“E3”)
Particles.CreateEmitter(“E6”, screenW*0.1, screenH*0.99, 0, false, true)
–local Properties = {}
Particles.CreateParticleType (“Shots6”,
{
imagePath = “images/eye1.png”,
imageWidth = 79,
imageHeight = 37,
velocityStart = 150,
– velocityVariation = 230,
autoOrientation = false,
killOutsideScreen = true,
lifeTime = 10000,
alphaStart = 1.00,
rotationVariation = 360,
emissionShape = 1,
emissionRadius = 450,

– APPLY PHYSICS:
PhysicsMaterial = { density = 0, friction = 0, bounce = 0 },
PhysicsProperties = { isFixedRotation = true, isSleepingAllowed = true, bodyType = “kinematic”, isSensor = true, name = “SHOT4” }
} )

Particles.AttachParticleType(“E6”, “Shots6”, 0.5, 99999,0)
–Particles.SetEmitterTarget(“E6”, “Shots6”, false)
local Emitter6 = Particles.GetEmitter(“E6”)
localGroup:insert(Emitter6)
Particles.StartEmitter(“E6”)

– CREATE EMITTERS (NAME, SCREENW, SCREENH, ROTATION, ISVISIBLE, LOOP)
Particles.CreateEmitter(“E4”, screenW*0.9, screenH*0.9, 0, false, false)
Particles.CreateEmitter(“E5”, screenW*0.1, screenH*0.9, 0, false, false)
–local Properties = {}
– DEFINE PARTICLE TYPE PROPERTIES
Particles.CreateParticleType (“FairyDust”, {
imagePath = “images/colored_stars.png”,
imageWidth = 128,
imageHeight = 128,
velocityStart = 50,
–velocityVariation = 25,
directionVariation = 45,
alphaStart = 0,
alphaVariation = .5,
fadeInSpeed = 2.0,
fadeOutSpeed = -1.0,
fadeOutDelay = 1000,
scaleStart = 0.01,
scaleVariation = 0.25,
scaleInSpeed = 0.25,
weight = -0.6,
rotationVariation = 360,
rotationChange = 90,
emissionShape = 0,
killOutsideScreen = true,
lifeTime = 2000,
useEmitterRotation = false,
} )

– FEED EMITTERS (EMITTER NAME, PARTICLE TYPE NAME, EMISSION RATE, DURATION, DELAY)
Particles.AttachParticleType(“E4”, “FairyDust” , 10, 99999,0)
Particles.AttachParticleType(“E5”, “FairyDust” , 10, 99999,0)
– TRIGGER THE EMITTERS

local Emitter4 = Particles.GetEmitter(“E4”)
localGroup:insert(Emitter4)
Particles.StartEmitter(“E4”)

local Emitter5 = Particles.GetEmitter(“E5”)
localGroup:insert(Emitter5)
Particles.StartEmitter(“E5”)

– PHYSICS COLLISION LISTENER

local function onCollision( event )
if ( event.phase == “began” ) then
– THERE IS A SHOT INVOLVED?
local Particle
–SHOT 1
if event.object1.name == “SHOT” then
Particle = event.object1
sheTouch2 = “”
sheTouch3 =""
if sheTouch == “active” then
local newScore = gameScore + gamePoints
setScore( newScore )
local newPoints = gamePoints + 1
setPoints( newPoints )
else
local newScore = gameScore + 1
setScore( newScore )
gamePoints = 0
sheTouch = “active”
end
–SHOT 2
elseif event.object1.name == “SHOT2” then
Particle = event.object1
sheTouch = “”
sheTouch3 = “”
if sheTouch2 == “active” then
local newScore = gameScore + gamePoints
setScore( newScore )

local newPoints = gamePoints + 2
setPoints( newPoints )
else
local newScore = gameScore + 2
setScore( newScore )
gamePoints = 0
sheTouch2 = “active”
end
–SHOT 3
elseif event.object1.name == “SHOT3” then
Particle = event.object1
sheTouch = “”
sheTouch2 = “”
if sheTouch3 == “active” then
local newScore = gameScore + gamePoints
setScore( newScore )

local newPoints = gamePoints + 3
setPoints( newPoints )
else
local newScore = gameScore + 3
setScore( newScore )
gamePoints = 0
sheTouch3 = “active”
end
–SHOT 4
elseif event.object1.name == “SHOT4” then
Particle = event.object1
sheTouch = “”
sheTouch2 = “”
sheTouch3 = “”
local newScore = gameScore - 10
setScore( newScore )
–END
elseif
event.object2.name == “SHOT” or “SHOT2” or “SHOT3” or “SHOT4” then
Particle = event.object2
end

if Particle ~= nil then
Particle.killTime = system.getTimer()
if Enemy.Transition ~= nil then transition.cancel(Enemy.Transition) end
Enemy.xScale, Enemy.yScale = 1.25, 1.25
Enemy.Transition = transition.to (Enemy, { xScale = 1, yScale = 1, time = 250 } )
end
end
end

Runtime:addEventListener( “collision”, onCollision )

local function main( event )
Particles.Update()
end

Runtime:addEventListener( “enterFrame”, main )

local gameStart = function()

hud()
gameActivate()
local gameTimer = timer.performWithDelay( 1000, function() startTimer(); end, 1 )
local highScoreFilename = “highScore4.data”
local loadedHighScore = loadValue( highScoreFilename )
highScore = tonumber(loadedHighScore)

end

gameStart()

return localGroup

end

return level4 [/lua] [import]uid: 105289 topic_id: 35652 reply_id: 335652[/import]

Tehis,

FWIW, I have a physics app and I had the same problem, I searched and tried most everything to find why my game would slow down to 30 FPS from 60 FPS after the app was either restarted or the home button was pushed on iOS. I tried different things for over a month to solve the problem as I was developing the game. I could continue to develop because on a clean load to the device, I would delete the old version then install the new build and the game played at a perfect 60 FPS until suspended.

One day I as looking at my config.lua, I’ve been reusing the same one for a long time, to disable Launchpad and I noticed I had “antialias = true” declared. If not declared, it defaults to false now I believe.

Anyways, I set it to false and it solved my problem, I was thrilled!

I’d check your config.lua., who knows.

Nail

[import]uid: 106779 topic_id: 35652 reply_id: 141757[/import]

@John Junior,
Inaccurate and unhelpful as usual. Par for the course at this point.

@Tehis Kangelane,
We (the community) appreciate the code, but for people (including staff) to help you, you’ll get a better response if you narrow down your issue by following “standard” coding diagnostic processes. You’re using two 3rd-party tools (Director and Particle Candy), so the issue could likely be outside of the Corona core. You might find a very generous developer here on the forums who is willing to look through your code, but again, it helps if you narrow down the issue as much as possible.

Since your code is generating no errors, but it’s slowing down on each restart over time, the issue is likely a memory leak caused by something you did not clean up properly on the DIrector scene restart.

If you can narrow down your code, and re-post, then the community will likely come to your assistance. Most of us actually want to help other developers, but we’re all extremely busy. An isolated, proven test-case is much easier to diagnose than an entire module of code.

Sincerely,
Brent Sorrentino [import]uid: 200026 topic_id: 35652 reply_id: 141786[/import]

hi Tehis Kangelane,

Since this is your stripped down code i may be wrong but here what I noticed.

  1. You have clean functions (more than once) but not called upon. Thus your Particles.CleanUp function is not called to clear from memory.

  2. Your emiitter handles, Emitter1, Emitter2 and so on are not nil out so they will not be garbage collected.

You should see Particle Candy debug statement in terminal to see whats going on.

As Brent said this is 3rd party tools so you can either put your question in Particle Candy sub-forum or email X-Pressive directly.

Good Luck!

burhan
[import]uid: 74883 topic_id: 35652 reply_id: 141829[/import]

Thank you all for the answers - tried them all and also tons of other solutions this week but no luck (adding emitters to groups, removing them, creating timerStashs, extra cleaning groups, clean group library etc) .
Seems that particle candy is not the issue but a memory leak, so my question would be - For the level part, am I doing things right? I removed the particle part and leaved only the level basic stuff to keep it more clear. So what I´m doing:

  1. starting level (line 1)
  2. Including external libraries (line 8)
  3. defining variables and sounds (line 12)
  4. checking level info and including highscore load/save part (line 78)
  5. creating function game is active, with a variable value and background music (line 134)
  6. function to update score (line 144)
  7. function to update bonus score (line 157)
  8. game over function (line 174)
  • stopping background music and removing it
  • nil gametimer and assets
  • stopping physics
  • removing runtime eventlisteners

now if the game score is 20 or bigger while the function is called a victory screen is added, new level key for next level, score assets and next level button is available. Here I add cleanGroup (just in case) to clear the localGroup assets.
If the game score is 19 or smaller while game over is called game over screen is added with restar option. Again I´m adding the cleanGroup function before change scene.

Am I missing something here? The memory keeps constantly growing here with:

First level start:
MemUsage 194.1
TextMem 4.7

First level after restart:
MemUsage 211.5
TextMem 4.7

First level second restart:
MemUsage 215.6
TextMem 4.7

First level third restart:
MemUsage 219.5
TextMem 4.7

etc
9. the game timer function will let the game run for given seconds and then call game over (line 370)
10. hud function with ingame hud texts (line 387)
11. function to make player character draggable (line 437)
12. player character (line 461)
13. collision part - I left it in for reference, worked with particle candy emitters (line 471)
14. gamestart function, adding hud, activating game, writing highscore data (line 521)
15. run gamestart (line 534)
16. return local group and level (line 536)

Been struggling for two weeks now with no success and going slightly mad :slight_smile:
The concept of the game is changed just to make it work. I admit I was dumb not to test it on an actual device with longer sessions and created all levels etc.

Maybe if someone of you has the time to look over the level part and evaluate it? Does it make sense or am I making some huge mistakes which will lead to such memory leaks ( I also have a small 5mb stripped version of the game with menus and a few levels with random logic if someone would have time to spear).
I do not want to use your time for free so maybe we could find out a reward (whoever has some ideas) for help.

Thank you!

Code:

[lua]

local level1 = {}

level1.new = function( params )

local localGroup = display.newGroup()

local physics = require “physics”
local ui = require “ui”

local screenW = display.contentWidth
local screenH = display.contentHeight

physics.start()
physics.setGravity (0,0)

local background
local menuBtn

local counter
local timerInfo
local numSeconds = 30

local gamePoints = 0
local pointsText
local scoreText
local highScoreText
local shade
local gameOverScreen
local gameIsActive = false

local gameScore = 0
local highScore

local Enemy
local sheTouch = “”
local she2Touch = “”

local backgroundSound = audio.loadSound(“sounds/METROO.mp3”)
local backgroundSoundA = audio.loadSound(“sounds/METROOamb.mp3”)
local gameOverSound = audio.loadSound( “sounds/gameover.mp3” )
local btnSound = audio.loadSound( “sounds/btnSound.wav” )
timerStash = {}
transitionStash = {}

function cancelAllTimers()
local k, v

for k,v in pairs(timerStash) do
timer.cancel( v )
v = nil; k = nil
end

timerStash = nil
timerStash = {}
end

function cancelAllTransitions()
local k, v

for k,v in pairs(transitionStash) do
transition.cancel( v )
v = nil; k = nil
end

transitionStash = nil
transitionStash = {}
end

–Get the current unlocked level value
currentLevel = loadFile(“currentLevel.txt”)
print “Level 1”

– first add save values from Beebe’s class

–***************************************************

– saveValue() --> used for saving high score, etc.

–***************************************************
local saveValue = function( strFilename, strValue )
– will save specified value to specified file
local theFile = strFilename
local theValue = strValue

local path = system.pathForFile( theFile, system.DocumentsDirectory )

– io.open opens a file at path. returns nil if no file found
local file = io.open( path, “w+” )
if file then
– write game score to the text file
file:write( theValue )
io.close( file )
end
end

–***************************************************

– loadValue() --> load saved value from file (returns loaded value as string)

–***************************************************
local loadValue = function( strFilename )
– will load specified file, or create new file if it doesn’t exist

local theFile = strFilename

local path = system.pathForFile( theFile, system.DocumentsDirectory )

– io.open opens a file at path. returns nil if no file found
local file = io.open( path, “r” )
if file then
– read all contents of file into a string
local contents = file:read( “*a” )
io.close( file )
return contents
else
– create file b/c it doesn’t exist yet
file = io.open( path, “w” )
file:write( “0” )
io.close( file )
return “0”
end
end

local gameActivate = function()

gameIsActive = true
myMusic = audio.play( backgroundSound, { channel=1, loops=-1 } )
myMusicA = audio.play( backgroundSoundA, {channel=2, loops=-1, volume=0.5 } )

end

local setScore = function( scoreNum )

local newScore = scoreNum
gameScore = newScore

if gameScore < 0 then gameScore = 0; end

scoreText.text = "Love: " … tostring( gameScore )
scoreText.xScale = 0.5; scoreText.yScale = 0.5
scoreText.x = 40
scoreText.y = 15
end

local setPoints = function( pointsNum )

local newPoints = pointsNum
gamePoints = newPoints

if gamePoints < 0 then gamePoints = 0; end
pointsText.text = "Luck: " … tostring( gamePoints )
pointsText.xScale = 0.5; pointsText.yScale = 0.5
pointsText.x = 40
pointsText.y = 35

end

–***************************************************
– CALL GAMEOVER OR VICTORY
–***************************************************
local callGameOver = function()

audio.stop(1)
audio.dispose(backgroundSound)
backgroundSound = nil
mainMusic = nil

audio.stop(2)
audio.dispose(backgroundSoundA)
backgroundSoundA = nil
mainAmbient = nil
if gameTimer then timer.cancel(gameTimer) end
gameTimer = nil

display.remove( background )
background = nil

display.remove( Enemy )
Enemy = nil

gameIsActive = false
physics.stop()
Runtime:removeEventListener( “collision”, onCollision )
–Runtime:removeEventListener( “enterFrame”, main )
–Particles.CleanUp()

if gameScore >= 20 then
shade = display.newRect( 0, 0, 480, 320 )
shade:setFillColor( 0, 0, 0, 255 )
shade.x = 240; shade.y = 160
shade.alpha = 0
victoryScreen = display.newImageRect( “images/victoryScreen.png”, 480, 320 )
victoryScreen.x = 240; victoryScreen.y = 160
victoryScreen.alpha = 0
localGroup:insert( shade )
localGroup:insert( victoryScreen )

if tonumber(currentLevel) < 2 then
saveFile(“currentLevel.txt”, 2)
end

local onNextTouch = function( event )
if event.phase == “release” then
audio.play( buttonSound )
cleanGroup( localGroup )
localGroup = nil
director:changeScene( “loadLevels” )
end
end

nextBtn = ui.newButton{
defaultSrc = “images/nextbtn.png”,
defaultX = 84,
defaultY = 34,
overSrc = “images/nextbtn-over.png”,
overX = 84,
overY = 34,
onEvent = onNextTouch,
id = “LevelButton”,
text = “”,
font = “Helvetica”,
textColor = { 255, 255, 255, 255 },
size = 16,
emboss = false
}

nextBtn.x = 430; nextBtn.y = 305
localGroup:insert( nextBtn )

else
gameoverMusic = audio.play( gameOverSound, {channel=3, loops=0 } )
shade = display.newRect( 0, 0, 480, 320 )
shade:setFillColor( 0, 0, 0, 255 )
shade.x = 240; shade.y = 160
shade.alpha = 0
gameOverScreen = display.newImageRect( “images/gameOver.png”, 480, 320 )
gameOverScreen.x = 240; gameOverScreen.y = 160
gameOverScreen.alpha = 0
localGroup:insert( shade )
localGroup:insert( gameOverScreen )

local onRestartTouch = function( event )

if event.phase == “release” then
audio.stop(3)
audio.dispose(gameOverSound)
gameOverSound = nil
gameoverMusic = nil
audio.play( buttonSound )
cleanGroup( localGroup )
localGroup = nil
cancelAllTransitions()
cancelAllTimers()
director:changeScene( “load” )
end
end

restBtn = ui.newButton{
defaultSrc = “images/restartbtn.png”,
defaultX = 84,
defaultY = 34,
overSrc = “images/restartbtn-over.png”,
overX = 84,
overY = 34,
onEvent = onRestartTouch,
id = “RestartButton”,
text = “”,
font = “Helvetica”,
textColor = { 255, 255, 255, 255 },
size = 16,
emboss = false
}

restBtn.x = 440; restBtn.y = 305
localGroup:insert( restBtn )
end

local newScore = gameScore
setScore( newScore )
–TRANSITION VICTORY ASSETS
transitionStash.newTransitionC = transition.to( shade, { time=200, alpha=0.65 } )
transitionStash.newTransitionD = transition.to( victoryScreen, { time=500, alpha=1 } )
–TRANSITION GAME OVER ASSETS
transitionStash.newTransitionE = transition.to( shade, { time=200, alpha=0.65 } )
transitionStash.newTransitionF = transition.to( gameOverScreen, { time=500, alpha=1 } )

scoreText.isVisible = false
scoreText.text = "Last Love: " … tostring( gameScore + gamePoints )
scoreText:setTextColor( 255, 255, 255 )
scoreText.xScale = 0.5; scoreText.yScale = 0.5 --> for clear retina display text
scoreText.x = 240
scoreText.y = 185
scoreText:toFront()
timerStash.newTimerA = timer.performWithDelay( 0, function() scoreText.isVisible = true; end, 1 )

– Compare scores
if gameScore > highScore then
highScore = gameScore
local highScoreFilename = “highScore1.data”
saveValue( highScoreFilename, tostring(highScore) )
end

– SHOW HIGH SCORE
highScoreText = display.newText( "Deepest Love: " … tostring( highScore ), 0, 0, “Buxton Sketch”, 36 )
highScoreText:setTextColor( 255, 255, 255 )
highScoreText.xScale = 0.5; highScoreText.yScale = 0.5
highScoreText.x = 240
highScoreText.y = 204

localGroup:insert( highScoreText )

local onMenuTouch = function( event )
if event.phase == “release” then
audio.stop(3)
audio.dispose(gameOverSound)
gameOverSound = nil
gameoverMusic = nil
audio.play( buttonSound )
cleanGroup( localGroup )
localGroup = nil
director:changeScene( “loadmainmenu” )
end
end

menuBtn = ui.newButton{
defaultSrc = “images/menubtn.png”,
defaultX = 75,
defaultY = 30,
overSrc = “images/menubtn-over.png”,
overX = 75,
overY = 30,
onEvent = onMenuTouch,
id = “MenuButton”,
text = “”,
font = “Helvetica”,
textColor = { 255, 255, 255, 255 },
size = 16,
emboss = false
}

menuBtn.x = 40; menuBtn.y = 305

localGroup:insert( menuBtn )
end

local background = display.newImageRect( “images/bg1.png”, 480, 320 )
background.x = 240; background.y = 160
localGroup:insert( background )
–***************************************************
– TIMER
–***************************************************
local myTimer = function()
numSeconds = numSeconds - 1
counter.text = "Left: " … tostring( numSeconds )
print( numSeconds )

if numSeconds < 1 then
timer.cancel( timerInfo )
restartTimer = timer.performWithDelay( 300, function() callGameOver(); end, 1 )
end
end

local startTimer = function()
print( “Start Timer” )
timerInfo = timer.performWithDelay( 1000, myTimer, 0 )
end

local hud = function()

scoreText = display.newText( "Love: " … tostring( gameScore ), 0, 0, “Buxton Sketch”, 44 )
scoreText:setTextColor( 255, 255, 255 )
scoreText.xScale = 0.5; scoreText.yScale = 0.5
scoreText.x = 40
scoreText.y = 15

localGroup:insert( scoreText )

counter = display.newText( "Left: " … tostring( numSeconds ), 0, 0, “Buxton Sketch”, 44 )
counter:setTextColor( 255,255,255 )
counter.xScale = 0.5; counter.yScale = 0.5
counter.x = 430
counter.y = 15

localGroup:insert( counter )
pointsText = display.newText( "Luck: " … tostring( gamePoints ), 0, 0, “Buxton Sketch”, 44 )
pointsText:setTextColor( 255, 255, 255 )
pointsText.xScale = 0.5; pointsText.yScale = 0.5
pointsText.x = 40
pointsText.y = 35

localGroup:insert( pointsText )
levelText = display.newText( “Beginning 1: The Evening”, 0, 0, “Buxton Sketch”, 36 )
levelText:setTextColor( 255, 255, 255, 255 )
levelText.xScale = 0.5; levelText.yScale = 0.5
levelText.x = screenW/2
levelText.y = 17

localGroup:insert( levelText )
infoText = display.newText( “Move back and forth”, 0, 0, “Buxton Sketch”, 28 )
infoText:setTextColor( 255, 255, 255 )
infoText.xScale = 0.5; infoText.yScale = 0.5
infoText.x = screenW/2
infoText.y = 40
localGroup:insert( infoText )

return hud

end

local startDrag = function( event )
local Field = event.target
local phase = event.phase
if “began” == phase then
display.getCurrentStage():setFocus( Field )
Field.isFocus = true
Field.x0 = event.x - Field.x

elseif Field.isFocus then
if “moved” == phase then
Field.x = event.x - Field.x0
–Field.y = event.y - Field.y0
elseif “ended” == phase or “cancelled” == phase then
display.getCurrentStage():setFocus( nil )
Field.isFocus = false
end
end

– STOP FURTHER PROPAGATION OF TOUCH EVENT!
return true
end

– ENEMY
local Enemy = display.newImageRect(“images/paddle.png”, 67, 63)
Enemy.x = screenW* .5
Enemy.y = screenH*.9
Enemy.name = “ENEMY”
physics.addBody( Enemy, “dynamic”, { radius = 32 } )
localGroup:insert( Enemy )


– PHYSICS COLLISION LISTENER

local function onCollision( event )
if ( event.phase == “began” ) then
– THERE IS A SHOT INVOLVED?
local Particle
if event.object1.name == “SHOT” then
Particle = event.object1
sheTouch2 = “”
if sheTouch == “active” then
local newScore = gameScore + gamePoints
setScore( newScore )
local newPoints = gamePoints + 1
setPoints( newPoints )
else
local newScore = gameScore + 1
setScore( newScore )
gamePoints = 0
sheTouch = “active”
end
elseif event.object1.name == “SHOT2” then
Particle = event.object1
sheTouch = “”
if sheTouch2 == “active” then
local newScore = gameScore + gamePoints
setScore( newScore )

local newPoints = gamePoints + 1
setPoints( newPoints )
else
local newScore = gameScore + 1
setScore( newScore )
gamePoints = 0
sheTouch2 = “active”
end
elseif
event.object2.name == “SHOT” or “SHOT2” then
Particle = event.object2
end

if Particle ~= nil then
Particle.killTime = system.getTimer()
if Enemy.Transition ~= nil then transition.cancel(Enemy.Transition) end
Enemy.xScale, Enemy.yScale = 1.25, 1.25
Enemy.Transition = transition.to (Enemy, { xScale = 1, yScale = 1, time = 250 } )
end
end
end

Runtime:addEventListener( “collision”, onCollision )
local gameStart = function()

hud()
gameActivate()
Enemy:addEventListener( “touch”, startDrag )

timerStash.gameTimer = timer.performWithDelay( 1000, function() startTimer(); end, 1 )
local highScoreFilename = “highScore1.data”
local loadedHighScore = loadValue( highScoreFilename )

highScore = tonumber(loadedHighScore)
end

gameStart()

return localGroup

end

return level1
[/lua]
[import]uid: 105289 topic_id: 35652 reply_id: 142227[/import]

Hi Tehis,
On lines 136-137, I notice you’re assigning audio handles to global variables (“myMusic” and “myMusicA”). I suggest you up-reference these to local variables (or named indexes within a table, for organizational purposes), then stop them and nil them out on level exit. Improper audio stopping, disposal, and handle cleanup is one of the most common causes of memory leaks.

Regards,
Brent [import]uid: 200026 topic_id: 35652 reply_id: 142392[/import]

Hey Brent, thanks for the advice, tried - still no luck, it is like the director is not clearing between levels (or I´m not telling it to clean right).

Having Memory somewhere around 170 when mainmenu is loaded the first time and after a few levels it stays pretty much where the level ends (on memory numbers, 300 or something). Texture memory is very stable and cleared out.

So I have tried all kind of stuff, together and alone:

[lua]
cleanGroup( localGroup )
localGroup = nil
local removeListeners = function()
if restBtn then
restBtn:removeEventListener( “touch”, restBtn )
end
if nextBtn then
nextBtn:removeEventListener( “touch”, nextBtn )
end
if menuBtn then
menuBtn:removeEventListener( “touch”, menutBtn )
end
end
removeListeners()
ui = nil
package.loaded[“ui”] = nil
physics = nil
package.loaded[“physics”] = nil
[/lua]

and different clean functions but nothing.

I have looked through these and many others with similar issues:

http://developer.coronalabs.com/forum/2012/11/30/dose-require-consume-memory

http://developer.coronalabs.com/forum/2011/01/14/how-do-i-tell-if-my-game-leaking

http://developer.coronalabs.com/forum/2012/05/26/ghosts-vs-monsters-memory-leak - Quiet the same issue, even bought the corona® profiler, but can’t actual analyze the data given (imo should have a better tutorial and use cases, not sure what I’m looking at).
I´m quite a beginner at lua, I must say, but previous games did not have such problems.

So again, I guess in the end I have to start over from zero (I guess storyboard then and different level system) or drop the project in overall, but would still hope for some suggestions. Still will try to find a solution.

https://www.dropbox.com/sh/3my9ep346yl1vgy/6XRrogmA_U shared it, levels have different “tests” and I actually feel that I´m floating away with each try. The gameplay is just for testing purposes, also the difference between level1 and level2.

Thanks. [import]uid: 105289 topic_id: 35652 reply_id: 142406[/import]

Tehis,

FWIW, I have a physics app and I had the same problem, I searched and tried most everything to find why my game would slow down to 30 FPS from 60 FPS after the app was either restarted or the home button was pushed on iOS. I tried different things for over a month to solve the problem as I was developing the game. I could continue to develop because on a clean load to the device, I would delete the old version then install the new build and the game played at a perfect 60 FPS until suspended.

One day I as looking at my config.lua, I’ve been reusing the same one for a long time, to disable Launchpad and I noticed I had “antialias = true” declared. If not declared, it defaults to false now I believe.

Anyways, I set it to false and it solved my problem, I was thrilled!

I’d check your config.lua., who knows.

Nail

[import]uid: 106779 topic_id: 35652 reply_id: 141757[/import]

@John Junior,
Inaccurate and unhelpful as usual. Par for the course at this point.

@Tehis Kangelane,
We (the community) appreciate the code, but for people (including staff) to help you, you’ll get a better response if you narrow down your issue by following “standard” coding diagnostic processes. You’re using two 3rd-party tools (Director and Particle Candy), so the issue could likely be outside of the Corona core. You might find a very generous developer here on the forums who is willing to look through your code, but again, it helps if you narrow down the issue as much as possible.

Since your code is generating no errors, but it’s slowing down on each restart over time, the issue is likely a memory leak caused by something you did not clean up properly on the DIrector scene restart.

If you can narrow down your code, and re-post, then the community will likely come to your assistance. Most of us actually want to help other developers, but we’re all extremely busy. An isolated, proven test-case is much easier to diagnose than an entire module of code.

Sincerely,
Brent Sorrentino [import]uid: 200026 topic_id: 35652 reply_id: 141786[/import]

hi Tehis Kangelane,

Since this is your stripped down code i may be wrong but here what I noticed.

  1. You have clean functions (more than once) but not called upon. Thus your Particles.CleanUp function is not called to clear from memory.

  2. Your emiitter handles, Emitter1, Emitter2 and so on are not nil out so they will not be garbage collected.

You should see Particle Candy debug statement in terminal to see whats going on.

As Brent said this is 3rd party tools so you can either put your question in Particle Candy sub-forum or email X-Pressive directly.

Good Luck!

burhan
[import]uid: 74883 topic_id: 35652 reply_id: 141829[/import]

Thank you all for the answers - tried them all and also tons of other solutions this week but no luck (adding emitters to groups, removing them, creating timerStashs, extra cleaning groups, clean group library etc) .
Seems that particle candy is not the issue but a memory leak, so my question would be - For the level part, am I doing things right? I removed the particle part and leaved only the level basic stuff to keep it more clear. So what I´m doing:

  1. starting level (line 1)
  2. Including external libraries (line 8)
  3. defining variables and sounds (line 12)
  4. checking level info and including highscore load/save part (line 78)
  5. creating function game is active, with a variable value and background music (line 134)
  6. function to update score (line 144)
  7. function to update bonus score (line 157)
  8. game over function (line 174)
  • stopping background music and removing it
  • nil gametimer and assets
  • stopping physics
  • removing runtime eventlisteners

now if the game score is 20 or bigger while the function is called a victory screen is added, new level key for next level, score assets and next level button is available. Here I add cleanGroup (just in case) to clear the localGroup assets.
If the game score is 19 or smaller while game over is called game over screen is added with restar option. Again I´m adding the cleanGroup function before change scene.

Am I missing something here? The memory keeps constantly growing here with:

First level start:
MemUsage 194.1
TextMem 4.7

First level after restart:
MemUsage 211.5
TextMem 4.7

First level second restart:
MemUsage 215.6
TextMem 4.7

First level third restart:
MemUsage 219.5
TextMem 4.7

etc
9. the game timer function will let the game run for given seconds and then call game over (line 370)
10. hud function with ingame hud texts (line 387)
11. function to make player character draggable (line 437)
12. player character (line 461)
13. collision part - I left it in for reference, worked with particle candy emitters (line 471)
14. gamestart function, adding hud, activating game, writing highscore data (line 521)
15. run gamestart (line 534)
16. return local group and level (line 536)

Been struggling for two weeks now with no success and going slightly mad :slight_smile:
The concept of the game is changed just to make it work. I admit I was dumb not to test it on an actual device with longer sessions and created all levels etc.

Maybe if someone of you has the time to look over the level part and evaluate it? Does it make sense or am I making some huge mistakes which will lead to such memory leaks ( I also have a small 5mb stripped version of the game with menus and a few levels with random logic if someone would have time to spear).
I do not want to use your time for free so maybe we could find out a reward (whoever has some ideas) for help.

Thank you!

Code:

[lua]

local level1 = {}

level1.new = function( params )

local localGroup = display.newGroup()

local physics = require “physics”
local ui = require “ui”

local screenW = display.contentWidth
local screenH = display.contentHeight

physics.start()
physics.setGravity (0,0)

local background
local menuBtn

local counter
local timerInfo
local numSeconds = 30

local gamePoints = 0
local pointsText
local scoreText
local highScoreText
local shade
local gameOverScreen
local gameIsActive = false

local gameScore = 0
local highScore

local Enemy
local sheTouch = “”
local she2Touch = “”

local backgroundSound = audio.loadSound(“sounds/METROO.mp3”)
local backgroundSoundA = audio.loadSound(“sounds/METROOamb.mp3”)
local gameOverSound = audio.loadSound( “sounds/gameover.mp3” )
local btnSound = audio.loadSound( “sounds/btnSound.wav” )
timerStash = {}
transitionStash = {}

function cancelAllTimers()
local k, v

for k,v in pairs(timerStash) do
timer.cancel( v )
v = nil; k = nil
end

timerStash = nil
timerStash = {}
end

function cancelAllTransitions()
local k, v

for k,v in pairs(transitionStash) do
transition.cancel( v )
v = nil; k = nil
end

transitionStash = nil
transitionStash = {}
end

–Get the current unlocked level value
currentLevel = loadFile(“currentLevel.txt”)
print “Level 1”

– first add save values from Beebe’s class

–***************************************************

– saveValue() --> used for saving high score, etc.

–***************************************************
local saveValue = function( strFilename, strValue )
– will save specified value to specified file
local theFile = strFilename
local theValue = strValue

local path = system.pathForFile( theFile, system.DocumentsDirectory )

– io.open opens a file at path. returns nil if no file found
local file = io.open( path, “w+” )
if file then
– write game score to the text file
file:write( theValue )
io.close( file )
end
end

–***************************************************

– loadValue() --> load saved value from file (returns loaded value as string)

–***************************************************
local loadValue = function( strFilename )
– will load specified file, or create new file if it doesn’t exist

local theFile = strFilename

local path = system.pathForFile( theFile, system.DocumentsDirectory )

– io.open opens a file at path. returns nil if no file found
local file = io.open( path, “r” )
if file then
– read all contents of file into a string
local contents = file:read( “*a” )
io.close( file )
return contents
else
– create file b/c it doesn’t exist yet
file = io.open( path, “w” )
file:write( “0” )
io.close( file )
return “0”
end
end

local gameActivate = function()

gameIsActive = true
myMusic = audio.play( backgroundSound, { channel=1, loops=-1 } )
myMusicA = audio.play( backgroundSoundA, {channel=2, loops=-1, volume=0.5 } )

end

local setScore = function( scoreNum )

local newScore = scoreNum
gameScore = newScore

if gameScore < 0 then gameScore = 0; end

scoreText.text = "Love: " … tostring( gameScore )
scoreText.xScale = 0.5; scoreText.yScale = 0.5
scoreText.x = 40
scoreText.y = 15
end

local setPoints = function( pointsNum )

local newPoints = pointsNum
gamePoints = newPoints

if gamePoints < 0 then gamePoints = 0; end
pointsText.text = "Luck: " … tostring( gamePoints )
pointsText.xScale = 0.5; pointsText.yScale = 0.5
pointsText.x = 40
pointsText.y = 35

end

–***************************************************
– CALL GAMEOVER OR VICTORY
–***************************************************
local callGameOver = function()

audio.stop(1)
audio.dispose(backgroundSound)
backgroundSound = nil
mainMusic = nil

audio.stop(2)
audio.dispose(backgroundSoundA)
backgroundSoundA = nil
mainAmbient = nil
if gameTimer then timer.cancel(gameTimer) end
gameTimer = nil

display.remove( background )
background = nil

display.remove( Enemy )
Enemy = nil

gameIsActive = false
physics.stop()
Runtime:removeEventListener( “collision”, onCollision )
–Runtime:removeEventListener( “enterFrame”, main )
–Particles.CleanUp()

if gameScore >= 20 then
shade = display.newRect( 0, 0, 480, 320 )
shade:setFillColor( 0, 0, 0, 255 )
shade.x = 240; shade.y = 160
shade.alpha = 0
victoryScreen = display.newImageRect( “images/victoryScreen.png”, 480, 320 )
victoryScreen.x = 240; victoryScreen.y = 160
victoryScreen.alpha = 0
localGroup:insert( shade )
localGroup:insert( victoryScreen )

if tonumber(currentLevel) < 2 then
saveFile(“currentLevel.txt”, 2)
end

local onNextTouch = function( event )
if event.phase == “release” then
audio.play( buttonSound )
cleanGroup( localGroup )
localGroup = nil
director:changeScene( “loadLevels” )
end
end

nextBtn = ui.newButton{
defaultSrc = “images/nextbtn.png”,
defaultX = 84,
defaultY = 34,
overSrc = “images/nextbtn-over.png”,
overX = 84,
overY = 34,
onEvent = onNextTouch,
id = “LevelButton”,
text = “”,
font = “Helvetica”,
textColor = { 255, 255, 255, 255 },
size = 16,
emboss = false
}

nextBtn.x = 430; nextBtn.y = 305
localGroup:insert( nextBtn )

else
gameoverMusic = audio.play( gameOverSound, {channel=3, loops=0 } )
shade = display.newRect( 0, 0, 480, 320 )
shade:setFillColor( 0, 0, 0, 255 )
shade.x = 240; shade.y = 160
shade.alpha = 0
gameOverScreen = display.newImageRect( “images/gameOver.png”, 480, 320 )
gameOverScreen.x = 240; gameOverScreen.y = 160
gameOverScreen.alpha = 0
localGroup:insert( shade )
localGroup:insert( gameOverScreen )

local onRestartTouch = function( event )

if event.phase == “release” then
audio.stop(3)
audio.dispose(gameOverSound)
gameOverSound = nil
gameoverMusic = nil
audio.play( buttonSound )
cleanGroup( localGroup )
localGroup = nil
cancelAllTransitions()
cancelAllTimers()
director:changeScene( “load” )
end
end

restBtn = ui.newButton{
defaultSrc = “images/restartbtn.png”,
defaultX = 84,
defaultY = 34,
overSrc = “images/restartbtn-over.png”,
overX = 84,
overY = 34,
onEvent = onRestartTouch,
id = “RestartButton”,
text = “”,
font = “Helvetica”,
textColor = { 255, 255, 255, 255 },
size = 16,
emboss = false
}

restBtn.x = 440; restBtn.y = 305
localGroup:insert( restBtn )
end

local newScore = gameScore
setScore( newScore )
–TRANSITION VICTORY ASSETS
transitionStash.newTransitionC = transition.to( shade, { time=200, alpha=0.65 } )
transitionStash.newTransitionD = transition.to( victoryScreen, { time=500, alpha=1 } )
–TRANSITION GAME OVER ASSETS
transitionStash.newTransitionE = transition.to( shade, { time=200, alpha=0.65 } )
transitionStash.newTransitionF = transition.to( gameOverScreen, { time=500, alpha=1 } )

scoreText.isVisible = false
scoreText.text = "Last Love: " … tostring( gameScore + gamePoints )
scoreText:setTextColor( 255, 255, 255 )
scoreText.xScale = 0.5; scoreText.yScale = 0.5 --> for clear retina display text
scoreText.x = 240
scoreText.y = 185
scoreText:toFront()
timerStash.newTimerA = timer.performWithDelay( 0, function() scoreText.isVisible = true; end, 1 )

– Compare scores
if gameScore > highScore then
highScore = gameScore
local highScoreFilename = “highScore1.data”
saveValue( highScoreFilename, tostring(highScore) )
end

– SHOW HIGH SCORE
highScoreText = display.newText( "Deepest Love: " … tostring( highScore ), 0, 0, “Buxton Sketch”, 36 )
highScoreText:setTextColor( 255, 255, 255 )
highScoreText.xScale = 0.5; highScoreText.yScale = 0.5
highScoreText.x = 240
highScoreText.y = 204

localGroup:insert( highScoreText )

local onMenuTouch = function( event )
if event.phase == “release” then
audio.stop(3)
audio.dispose(gameOverSound)
gameOverSound = nil
gameoverMusic = nil
audio.play( buttonSound )
cleanGroup( localGroup )
localGroup = nil
director:changeScene( “loadmainmenu” )
end
end

menuBtn = ui.newButton{
defaultSrc = “images/menubtn.png”,
defaultX = 75,
defaultY = 30,
overSrc = “images/menubtn-over.png”,
overX = 75,
overY = 30,
onEvent = onMenuTouch,
id = “MenuButton”,
text = “”,
font = “Helvetica”,
textColor = { 255, 255, 255, 255 },
size = 16,
emboss = false
}

menuBtn.x = 40; menuBtn.y = 305

localGroup:insert( menuBtn )
end

local background = display.newImageRect( “images/bg1.png”, 480, 320 )
background.x = 240; background.y = 160
localGroup:insert( background )
–***************************************************
– TIMER
–***************************************************
local myTimer = function()
numSeconds = numSeconds - 1
counter.text = "Left: " … tostring( numSeconds )
print( numSeconds )

if numSeconds < 1 then
timer.cancel( timerInfo )
restartTimer = timer.performWithDelay( 300, function() callGameOver(); end, 1 )
end
end

local startTimer = function()
print( “Start Timer” )
timerInfo = timer.performWithDelay( 1000, myTimer, 0 )
end

local hud = function()

scoreText = display.newText( "Love: " … tostring( gameScore ), 0, 0, “Buxton Sketch”, 44 )
scoreText:setTextColor( 255, 255, 255 )
scoreText.xScale = 0.5; scoreText.yScale = 0.5
scoreText.x = 40
scoreText.y = 15

localGroup:insert( scoreText )

counter = display.newText( "Left: " … tostring( numSeconds ), 0, 0, “Buxton Sketch”, 44 )
counter:setTextColor( 255,255,255 )
counter.xScale = 0.5; counter.yScale = 0.5
counter.x = 430
counter.y = 15

localGroup:insert( counter )
pointsText = display.newText( "Luck: " … tostring( gamePoints ), 0, 0, “Buxton Sketch”, 44 )
pointsText:setTextColor( 255, 255, 255 )
pointsText.xScale = 0.5; pointsText.yScale = 0.5
pointsText.x = 40
pointsText.y = 35

localGroup:insert( pointsText )
levelText = display.newText( “Beginning 1: The Evening”, 0, 0, “Buxton Sketch”, 36 )
levelText:setTextColor( 255, 255, 255, 255 )
levelText.xScale = 0.5; levelText.yScale = 0.5
levelText.x = screenW/2
levelText.y = 17

localGroup:insert( levelText )
infoText = display.newText( “Move back and forth”, 0, 0, “Buxton Sketch”, 28 )
infoText:setTextColor( 255, 255, 255 )
infoText.xScale = 0.5; infoText.yScale = 0.5
infoText.x = screenW/2
infoText.y = 40
localGroup:insert( infoText )

return hud

end

local startDrag = function( event )
local Field = event.target
local phase = event.phase
if “began” == phase then
display.getCurrentStage():setFocus( Field )
Field.isFocus = true
Field.x0 = event.x - Field.x

elseif Field.isFocus then
if “moved” == phase then
Field.x = event.x - Field.x0
–Field.y = event.y - Field.y0
elseif “ended” == phase or “cancelled” == phase then
display.getCurrentStage():setFocus( nil )
Field.isFocus = false
end
end

– STOP FURTHER PROPAGATION OF TOUCH EVENT!
return true
end

– ENEMY
local Enemy = display.newImageRect(“images/paddle.png”, 67, 63)
Enemy.x = screenW* .5
Enemy.y = screenH*.9
Enemy.name = “ENEMY”
physics.addBody( Enemy, “dynamic”, { radius = 32 } )
localGroup:insert( Enemy )


– PHYSICS COLLISION LISTENER

local function onCollision( event )
if ( event.phase == “began” ) then
– THERE IS A SHOT INVOLVED?
local Particle
if event.object1.name == “SHOT” then
Particle = event.object1
sheTouch2 = “”
if sheTouch == “active” then
local newScore = gameScore + gamePoints
setScore( newScore )
local newPoints = gamePoints + 1
setPoints( newPoints )
else
local newScore = gameScore + 1
setScore( newScore )
gamePoints = 0
sheTouch = “active”
end
elseif event.object1.name == “SHOT2” then
Particle = event.object1
sheTouch = “”
if sheTouch2 == “active” then
local newScore = gameScore + gamePoints
setScore( newScore )

local newPoints = gamePoints + 1
setPoints( newPoints )
else
local newScore = gameScore + 1
setScore( newScore )
gamePoints = 0
sheTouch2 = “active”
end
elseif
event.object2.name == “SHOT” or “SHOT2” then
Particle = event.object2
end

if Particle ~= nil then
Particle.killTime = system.getTimer()
if Enemy.Transition ~= nil then transition.cancel(Enemy.Transition) end
Enemy.xScale, Enemy.yScale = 1.25, 1.25
Enemy.Transition = transition.to (Enemy, { xScale = 1, yScale = 1, time = 250 } )
end
end
end

Runtime:addEventListener( “collision”, onCollision )
local gameStart = function()

hud()
gameActivate()
Enemy:addEventListener( “touch”, startDrag )

timerStash.gameTimer = timer.performWithDelay( 1000, function() startTimer(); end, 1 )
local highScoreFilename = “highScore1.data”
local loadedHighScore = loadValue( highScoreFilename )

highScore = tonumber(loadedHighScore)
end

gameStart()

return localGroup

end

return level1
[/lua]
[import]uid: 105289 topic_id: 35652 reply_id: 142227[/import]

Hi Tehis,
On lines 136-137, I notice you’re assigning audio handles to global variables (“myMusic” and “myMusicA”). I suggest you up-reference these to local variables (or named indexes within a table, for organizational purposes), then stop them and nil them out on level exit. Improper audio stopping, disposal, and handle cleanup is one of the most common causes of memory leaks.

Regards,
Brent [import]uid: 200026 topic_id: 35652 reply_id: 142392[/import]

Hey Brent, thanks for the advice, tried - still no luck, it is like the director is not clearing between levels (or I´m not telling it to clean right).

Having Memory somewhere around 170 when mainmenu is loaded the first time and after a few levels it stays pretty much where the level ends (on memory numbers, 300 or something). Texture memory is very stable and cleared out.

So I have tried all kind of stuff, together and alone:

[lua]
cleanGroup( localGroup )
localGroup = nil
local removeListeners = function()
if restBtn then
restBtn:removeEventListener( “touch”, restBtn )
end
if nextBtn then
nextBtn:removeEventListener( “touch”, nextBtn )
end
if menuBtn then
menuBtn:removeEventListener( “touch”, menutBtn )
end
end
removeListeners()
ui = nil
package.loaded[“ui”] = nil
physics = nil
package.loaded[“physics”] = nil
[/lua]

and different clean functions but nothing.

I have looked through these and many others with similar issues:

http://developer.coronalabs.com/forum/2012/11/30/dose-require-consume-memory

http://developer.coronalabs.com/forum/2011/01/14/how-do-i-tell-if-my-game-leaking

http://developer.coronalabs.com/forum/2012/05/26/ghosts-vs-monsters-memory-leak - Quiet the same issue, even bought the corona® profiler, but can’t actual analyze the data given (imo should have a better tutorial and use cases, not sure what I’m looking at).
I´m quite a beginner at lua, I must say, but previous games did not have such problems.

So again, I guess in the end I have to start over from zero (I guess storyboard then and different level system) or drop the project in overall, but would still hope for some suggestions. Still will try to find a solution.

https://www.dropbox.com/sh/3my9ep346yl1vgy/6XRrogmA_U shared it, levels have different “tests” and I actually feel that I´m floating away with each try. The gameplay is just for testing purposes, also the difference between level1 and level2.

Thanks. [import]uid: 105289 topic_id: 35652 reply_id: 142406[/import]