Performance tips for rocket smoke trail(s)?

We have used the Particle Designer for creating smoke for flying rockets. But in general we noticed when we have some particle systems on screen simultaneously that this will slow down performance really really heavy.

So is there a solution to create some smoke trails which allows a lot of them to appear on screen simultaneously without to much performance costs?

Is it maybe better to work with images and transitions for the smoke? But I guess this will also allow only some rockets flying around at the same time, right?

Any ideas, tips? :slight_smile:

local fpsvaleur=fpschoisi-vitessejeu -- calcul the number of fps (depending of the fast of the game x2 ...) print("fps "..fpsvaleur) if fpsvaleur\>1 then fpsvaleur=mathrandom(1,((fpsvaleur-1)\*50)) end print("fps choisi "..fpschoisi.." fpsvaleur "..fpsvaleur) if fpsvaleur==1 then local dist1=10 -- dispersion of the smoke local dist3=20 local randomvalue=-1 local randomvalue1=0 local posix=your coordinate local posiy=your coordinate for i=1,3 do randomvalue1=randomvalue randomvalue=math.random(0,dist1) local sang=display.newCircle(posix+randomvalue-dist1\*0.5,posiy+randomvalue1\*0.8-dist1\*0.5\*0.8,dist3) dist1=dist1+30 dist3=dist3-6 if niveauch\<=4 or niveauch\>8 then sang:setFillColor(0.5,0.5,0.5,0.1) else sang:setFillColor(0.5,0.5,0.5,0.05) end --groupsang:insert(sang) if numgroup==nil then sang.group=mathfloor(sang.y)+1024+2 else sang.group=numgroup end group[sang.group]:insert(sang) local function destrucblood2(event) jeupause.timerlibre[event.source.num]=0 if sang~=nil then group[sang.group]:remove(sang) sang:removeSelf() sang=nil end end local destrucblood2=timer.performWithDelay(2500/(4-i)\*vitessejeuin,destrucblood2) -- time of display of the smoke destrucblood2.num=timerpause(3,destrucblood2) end end

I have done that and it work properly. I have add also a system who display less smoke when the game lose some fps

@d.mach - remiduchalard is making his own particles here, but the same concept applies for display.newEmitter() .
 

  1. You can use this kind of logic to reduce the number of emitters you create.
     

  2. You can use this to (as you create them) reduce the number of particles defined in the particle record (or increase to a known max if FPS are fine.)
     
     
    @remiduchalard,
     
    Hi.  I read your code, and (if I understand it correctly) I think you can get an additional performance boost with these changes to your example:

    – -- If ‘group’ in your code is actually just a table… – -- Use a common/shared function so you don’t spend time and memory creating – new ones for each particle – If you can define this at the file-level it will be them most efficient and beneficial. – Having it just before the loop as I show it here is ONLY a LITTLE beneficial. – The idea is you only DEFINE it once. – local function destrucblood2( self ) – Wasn’t sure what this was --jeupause.timerlibre[event.source.num]=0 self.group[self] = nil display.remove( self ) end if fpsvaleur==1 then local dist1=10 local dist3=20 local randomvalue=-1 local randomvalue1=0 local posix=your coordinate local posiy=your coordinate for i=1,3 do randomvalue1=randomvalue randomvalue=math.random(0,dist1) local sang=display.newCircle(posix+randomvalue-dist1*0.5,posiy+randomvalue1*0.8-dist1*0.5*0.8,dist3) dist1=dist1+30 dist3=dist3-6 if niveauch<=4 or niveauch>8 then sang:setFillColor(0.5,0.5,0.5,0.1) else sang:setFillColor(0.5,0.5,0.5,0.05) end group[sang] = sang sang.timer = destrucblood2 local destrucblood2=timer.performWithDelay(2500/(4-i)*vitessejeuin, sang ) destrucblood2.num=timerpause(3,destrucblood2) end end

The two things I did differently from you are:
 

  1. I used a common/shared timer function.  This reduces memory and creation/destruction/cleanup overhead
     
  2. I assumed that ‘group’ was actually just a table and simply used reference indexes instead to avoid those calls to insert() and remove().
     
    Note: If I misunderstood your usage, #1 may still be of some benefit.

Thank you so much for your help here remiduchalard and roaminggamer!

I just have tested the following code, based on the top one(s) and it seems to work fine. A good point to start working something out now.

local group={} local function destrucblood2( self ) &nbsp;&nbsp; -- Wasn't sure what this was &nbsp;&nbsp; --jeupause.timerlibre[event.source.num]=0 &nbsp;&nbsp; group[self] = nil &nbsp;&nbsp; --self.group[self] = nil &nbsp;&nbsp; display.remove( self ) &nbsp;&nbsp; self=nil end local showTest=function (xPos,yPos) &nbsp;&nbsp;&nbsp; --if fpsvaleur==1 then &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; local dist1=10 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; local dist3=20 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; local randomvalue=-1 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; local randomvalue1=0 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; local posix=xPos &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; local posiy=yPos &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; -- test: \*\*\*\*\*\*\*\*\* &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; local niveauch=5 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; local vitessejeuin=5 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; -- \*\*\*\*\*\*\*\*\*\*\*\*\*\*\* &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for i=1,3 do &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; randomvalue1=randomvalue &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; randomvalue=math.random(0,dist1) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; local sang=display.newCircle(posix+randomvalue-dist1\*0.5,posiy+randomvalue1\*0.8-dist1\*0.5\*0.8,dist3) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; dist1=dist1+30 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; dist3=dist3-6 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if niveauch\<=4 or niveauch\>8 then &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sang:setFillColor(0.5,0.5,0.5,0.1) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sang:setFillColor(0.5,0.5,0.5,0.05) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; end &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; group[sang] = sang &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sang.timer = destrucblood2 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; local destrucblood2=timer.performWithDelay(2500/(4-i)\*vitessejeuin, sang ) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; --destrucblood2.num=timerpause(3,destrucblood2) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; end &nbsp;&nbsp;&nbsp; --end end

Thx again!

@roaminggamer

Thank you for your message.

For information my array “group” is an array of display.newgroup()

It for my isometric engine. If something is far in the map I insert the image to group[high value]…

I don’t understand those line:

sang.timer = destrucblood2 local destrucblood2=timer.performWithDelay...

Can you explain me that?

To remove the object I don’t know if it’s faster to do that

group[sang.group]:remove(sang) sang:removeSelf() sang=nil

or 

sang:removeSelf() sang=nil

do you if it s usefull to set to nil?(because it’s a local value and it won’t be use anymore

For information, at the begining I create this code to display some blood.

This is help me to set a pause in the game. With that I can play and stop everything. It act like tag in transtition

jeupause.timerlibre[event.source.num]=0 ... destrucblood2.num=timerpause(3,destrucblood2)

Thanks

Timer

You can do this:

for i = 1, 10 local obj = display.newCircle( 10, 10 \* i, 10 ) timer.performWithDelay( 100 \* i, function() display.remove( obj ) end ) end

But this is more efficient since it only defines one function instead of 10 closures:

local function onTimer( self ) display.remove( self ) end for i = 1, 10 local obj = display.newCircle( 10, 10 \* i, 10 ) obj.timer = onTimer timer.performWithDelay( 100 \* i, obj ) end

obj:removeSelf()

Side note.  I never use removeSelf().  I prefer display.remove() because it is safer.

Setting locals to nil

If a variable is in fact local you don’t need to nil it.  It will self-destruct when it falls out of scope.

Table Remove versus nil Assign

This:

group[sang.group]:remove(sang) sang:removeSelf() sang=nil

is less efficient than this:

group[sang.group] = nil -- assuming sang.group is not a number display.remove(sang)

assuming that sang.group is NOT a number. i.e. if group is not a numerically indexed table you can simply nil the entry you are removing.  

The first version does a function call to remove, an unsafe call to removeSelf, and nils a local.

You can avoid all that using this kind of logic instead:

-- Just a demonstration of the concept not how you would do it specifically in your code -- -- My example uses a touch listener as the agent that decides when to delete the object, again -- just to demonstrate the concept of managing objects in a table. -- local trackingTable = {} local function onTouch( self, obj ) trackingTable[self] = nil -- clear the table index for this object (indexed by object reference) display.remove( self ) -- destroy the object... and done! end for 1, 100 do local obj = display.newCircle( math.random(10, 100), math.random(10, 100), 10 ) obj.touch = onTouch obj:addEventListener("touch") end

Regarding the use of the word group for a table

It is bad practice to use the word group anywhere in the name of a table, because it implies display group when in fact its just a table.

Just a note, but this made examining the code confusing and is still making this discussion a little hard to convey.

Timer Pause

Ah, yes I see.  I figured you must be using a pausing mechanism, but I was having a little trouble with the naming and indexing.

Cool and hope this helps a little.

Cheers,

Ed

is the

local trackingTable = {}

for deleting the left over objects using this table?

If so, how can it be used to delete the rest of the objects?

Thank you @roaminggamer

You made me discover something.

obj.timer = onTimer timer.performWithDelay( 100 \* i, obj )

I didn’t know it was possible. Thank you!

For group, I think you haven’t understand how I use it.

I use it for isometrics 3D

Initialization of the game:

group={} for i=1,2048 do group[i]=display.newGroup() end

Like this if I want to put something at x=10 and y=200.

I insert my object in group[200]

object=displ... object.x=10 object.y=199.8 object.group=math.floor(object.y) group[object.group]:insert(object)

For random value.

I don’t calculate 2 random value for the same object because is very heavy.

I use the random value of x for the next y value.

For pause:

function timerpause(letype,letimer,lenum) -- letype is the type of timer( because I don't want all timer set pause in the same condition and also change what to do when we set pause or quit the game. Does it finish instantly the timer, cancel it...) local num=nil -- letimer is the timer if lenum~=nil then -- lenum is the index in the table if we have already one num=lenum else local i=1 if modedelancement~=0 then i=4 end if letype==1 then while i\<=jeupause.timernb do if jeupause.timerlibre[i]==0 then num=i i=jeupause.timernb+1 else i=i+1 end end else i=jeupause.timernb while i\>=4 do if jeupause.timerlibre[i]==0 then num=i i=0 else i=i-1 end end end if num==nil then jeupause.timernb=jeupause.timernb+1 num=jeupause.timernb end end if jeupause.etat==1 then timer.pause(letimer) end if (removepartiel1==true and letype==1) or removetotal==true then -- remove partiel is when we relaunch the game and removetotal is when we leave the game timer.cancel(letimer) else if letype==4 and removepartiel1==true then timer.cancel(letimer) num=-1 else jeupause.timer[num]=letimer jeupause.timerlibre[num]=letype end end return(num) end

When we set the game on pause:

for i=1,jeupause.timernb,1 do if jeupause.timerlibre[i]==1 or jeupause.timerlibre[i]==3 or jeupause.timerlibre[i]==4 then if jeupause.timer[i]~=nil then timer.pause(jeupause.timer[i]) else jeupause.timerlibre[i]=0 end end end

What is the best way to keep track of timers and all generated graphics objects without to much overhead?

I have tried to reference all created timers (for rockets) in a table. And the same with the rocket trail objects.

But this is increasing the used mem very fast and too much.

Instead I’m right now only are using the .timer with self, like in the sample above BUT this allows almost no control over the timers and no control over the trail objects.

How can I keep track of the timers and obj, so I can cancel the timers with a scene change AND delete all the objects which are still there WITHOUT adding too much to the mem?

EDIT:

I think about doing the following: For each weapon I create a group like this:

weapon.objGroup=newGroup()

then I should be able to put all created bullets in the group.

newBullet=newImage…

weapon.objGroup:insert(newBullet)

Some get deleted, some will make it (life time) until the game scene is changing (for example to the main menu of the game). Then I should be able to cycle through all the still existing bullets by going through the groups children, right?

Is there a downside doing it like this to make sure I have removed all existing bullets in the scene before changing to another scene?

local fpsvaleur=fpschoisi-vitessejeu -- calcul the number of fps (depending of the fast of the game x2 ...) print("fps "..fpsvaleur) if fpsvaleur\>1 then fpsvaleur=mathrandom(1,((fpsvaleur-1)\*50)) end print("fps choisi "..fpschoisi.." fpsvaleur "..fpsvaleur) if fpsvaleur==1 then local dist1=10 -- dispersion of the smoke local dist3=20 local randomvalue=-1 local randomvalue1=0 local posix=your coordinate local posiy=your coordinate for i=1,3 do randomvalue1=randomvalue randomvalue=math.random(0,dist1) local sang=display.newCircle(posix+randomvalue-dist1\*0.5,posiy+randomvalue1\*0.8-dist1\*0.5\*0.8,dist3) dist1=dist1+30 dist3=dist3-6 if niveauch\<=4 or niveauch\>8 then sang:setFillColor(0.5,0.5,0.5,0.1) else sang:setFillColor(0.5,0.5,0.5,0.05) end --groupsang:insert(sang) if numgroup==nil then sang.group=mathfloor(sang.y)+1024+2 else sang.group=numgroup end group[sang.group]:insert(sang) local function destrucblood2(event) jeupause.timerlibre[event.source.num]=0 if sang~=nil then group[sang.group]:remove(sang) sang:removeSelf() sang=nil end end local destrucblood2=timer.performWithDelay(2500/(4-i)\*vitessejeuin,destrucblood2) -- time of display of the smoke destrucblood2.num=timerpause(3,destrucblood2) end end

I have done that and it work properly. I have add also a system who display less smoke when the game lose some fps

@d.mach - remiduchalard is making his own particles here, but the same concept applies for display.newEmitter() .
 

  1. You can use this kind of logic to reduce the number of emitters you create.
     

  2. You can use this to (as you create them) reduce the number of particles defined in the particle record (or increase to a known max if FPS are fine.)
     
     
    @remiduchalard,
     
    Hi.  I read your code, and (if I understand it correctly) I think you can get an additional performance boost with these changes to your example:

    – -- If ‘group’ in your code is actually just a table… – -- Use a common/shared function so you don’t spend time and memory creating – new ones for each particle – If you can define this at the file-level it will be them most efficient and beneficial. – Having it just before the loop as I show it here is ONLY a LITTLE beneficial. – The idea is you only DEFINE it once. – local function destrucblood2( self ) – Wasn’t sure what this was --jeupause.timerlibre[event.source.num]=0 self.group[self] = nil display.remove( self ) end if fpsvaleur==1 then local dist1=10 local dist3=20 local randomvalue=-1 local randomvalue1=0 local posix=your coordinate local posiy=your coordinate for i=1,3 do randomvalue1=randomvalue randomvalue=math.random(0,dist1) local sang=display.newCircle(posix+randomvalue-dist1*0.5,posiy+randomvalue1*0.8-dist1*0.5*0.8,dist3) dist1=dist1+30 dist3=dist3-6 if niveauch<=4 or niveauch>8 then sang:setFillColor(0.5,0.5,0.5,0.1) else sang:setFillColor(0.5,0.5,0.5,0.05) end group[sang] = sang sang.timer = destrucblood2 local destrucblood2=timer.performWithDelay(2500/(4-i)*vitessejeuin, sang ) destrucblood2.num=timerpause(3,destrucblood2) end end

The two things I did differently from you are:
 

  1. I used a common/shared timer function.  This reduces memory and creation/destruction/cleanup overhead
     
  2. I assumed that ‘group’ was actually just a table and simply used reference indexes instead to avoid those calls to insert() and remove().
     
    Note: If I misunderstood your usage, #1 may still be of some benefit.

Thank you so much for your help here remiduchalard and roaminggamer!

I just have tested the following code, based on the top one(s) and it seems to work fine. A good point to start working something out now.

local group={} local function destrucblood2( self ) &nbsp;&nbsp; -- Wasn't sure what this was &nbsp;&nbsp; --jeupause.timerlibre[event.source.num]=0 &nbsp;&nbsp; group[self] = nil &nbsp;&nbsp; --self.group[self] = nil &nbsp;&nbsp; display.remove( self ) &nbsp;&nbsp; self=nil end local showTest=function (xPos,yPos) &nbsp;&nbsp;&nbsp; --if fpsvaleur==1 then &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; local dist1=10 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; local dist3=20 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; local randomvalue=-1 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; local randomvalue1=0 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; local posix=xPos &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; local posiy=yPos &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; -- test: \*\*\*\*\*\*\*\*\* &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; local niveauch=5 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; local vitessejeuin=5 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; -- \*\*\*\*\*\*\*\*\*\*\*\*\*\*\* &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for i=1,3 do &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; randomvalue1=randomvalue &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; randomvalue=math.random(0,dist1) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; local sang=display.newCircle(posix+randomvalue-dist1\*0.5,posiy+randomvalue1\*0.8-dist1\*0.5\*0.8,dist3) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; dist1=dist1+30 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; dist3=dist3-6 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if niveauch\<=4 or niveauch\>8 then &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sang:setFillColor(0.5,0.5,0.5,0.1) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sang:setFillColor(0.5,0.5,0.5,0.05) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; end &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; group[sang] = sang &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sang.timer = destrucblood2 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; local destrucblood2=timer.performWithDelay(2500/(4-i)\*vitessejeuin, sang ) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; --destrucblood2.num=timerpause(3,destrucblood2) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; end &nbsp;&nbsp;&nbsp; --end end

Thx again!

@roaminggamer

Thank you for your message.

For information my array “group” is an array of display.newgroup()

It for my isometric engine. If something is far in the map I insert the image to group[high value]…

I don’t understand those line:

sang.timer = destrucblood2 local destrucblood2=timer.performWithDelay...

Can you explain me that?

To remove the object I don’t know if it’s faster to do that

group[sang.group]:remove(sang) sang:removeSelf() sang=nil

or 

sang:removeSelf() sang=nil

do you if it s usefull to set to nil?(because it’s a local value and it won’t be use anymore

For information, at the begining I create this code to display some blood.

This is help me to set a pause in the game. With that I can play and stop everything. It act like tag in transtition

jeupause.timerlibre[event.source.num]=0 ... destrucblood2.num=timerpause(3,destrucblood2)

Thanks

Timer

You can do this:

for i = 1, 10 local obj = display.newCircle( 10, 10 \* i, 10 ) timer.performWithDelay( 100 \* i, function() display.remove( obj ) end ) end

But this is more efficient since it only defines one function instead of 10 closures:

local function onTimer( self ) display.remove( self ) end for i = 1, 10 local obj = display.newCircle( 10, 10 \* i, 10 ) obj.timer = onTimer timer.performWithDelay( 100 \* i, obj ) end

obj:removeSelf()

Side note.  I never use removeSelf().  I prefer display.remove() because it is safer.

Setting locals to nil

If a variable is in fact local you don’t need to nil it.  It will self-destruct when it falls out of scope.

Table Remove versus nil Assign

This:

group[sang.group]:remove(sang) sang:removeSelf() sang=nil

is less efficient than this:

group[sang.group] = nil -- assuming sang.group is not a number display.remove(sang)

assuming that sang.group is NOT a number. i.e. if group is not a numerically indexed table you can simply nil the entry you are removing.  

The first version does a function call to remove, an unsafe call to removeSelf, and nils a local.

You can avoid all that using this kind of logic instead:

-- Just a demonstration of the concept not how you would do it specifically in your code -- -- My example uses a touch listener as the agent that decides when to delete the object, again -- just to demonstrate the concept of managing objects in a table. -- local trackingTable = {} local function onTouch( self, obj ) trackingTable[self] = nil -- clear the table index for this object (indexed by object reference) display.remove( self ) -- destroy the object... and done! end for 1, 100 do local obj = display.newCircle( math.random(10, 100), math.random(10, 100), 10 ) obj.touch = onTouch obj:addEventListener("touch") end

Regarding the use of the word group for a table

It is bad practice to use the word group anywhere in the name of a table, because it implies display group when in fact its just a table.

Just a note, but this made examining the code confusing and is still making this discussion a little hard to convey.

Timer Pause

Ah, yes I see.  I figured you must be using a pausing mechanism, but I was having a little trouble with the naming and indexing.

Cool and hope this helps a little.

Cheers,

Ed

is the

local trackingTable = {}

for deleting the left over objects using this table?

If so, how can it be used to delete the rest of the objects?

Thank you @roaminggamer

You made me discover something.

obj.timer = onTimer timer.performWithDelay( 100 \* i, obj )

I didn’t know it was possible. Thank you!

For group, I think you haven’t understand how I use it.

I use it for isometrics 3D

Initialization of the game:

group={} for i=1,2048 do group[i]=display.newGroup() end

Like this if I want to put something at x=10 and y=200.

I insert my object in group[200]

object=displ... object.x=10 object.y=199.8 object.group=math.floor(object.y) group[object.group]:insert(object)

For random value.

I don’t calculate 2 random value for the same object because is very heavy.

I use the random value of x for the next y value.

For pause:

function timerpause(letype,letimer,lenum) -- letype is the type of timer( because I don't want all timer set pause in the same condition and also change what to do when we set pause or quit the game. Does it finish instantly the timer, cancel it...) local num=nil -- letimer is the timer if lenum~=nil then -- lenum is the index in the table if we have already one num=lenum else local i=1 if modedelancement~=0 then i=4 end if letype==1 then while i\<=jeupause.timernb do if jeupause.timerlibre[i]==0 then num=i i=jeupause.timernb+1 else i=i+1 end end else i=jeupause.timernb while i\>=4 do if jeupause.timerlibre[i]==0 then num=i i=0 else i=i-1 end end end if num==nil then jeupause.timernb=jeupause.timernb+1 num=jeupause.timernb end end if jeupause.etat==1 then timer.pause(letimer) end if (removepartiel1==true and letype==1) or removetotal==true then -- remove partiel is when we relaunch the game and removetotal is when we leave the game timer.cancel(letimer) else if letype==4 and removepartiel1==true then timer.cancel(letimer) num=-1 else jeupause.timer[num]=letimer jeupause.timerlibre[num]=letype end end return(num) end

When we set the game on pause:

for i=1,jeupause.timernb,1 do if jeupause.timerlibre[i]==1 or jeupause.timerlibre[i]==3 or jeupause.timerlibre[i]==4 then if jeupause.timer[i]~=nil then timer.pause(jeupause.timer[i]) else jeupause.timerlibre[i]=0 end end end

What is the best way to keep track of timers and all generated graphics objects without to much overhead?

I have tried to reference all created timers (for rockets) in a table. And the same with the rocket trail objects.

But this is increasing the used mem very fast and too much.

Instead I’m right now only are using the .timer with self, like in the sample above BUT this allows almost no control over the timers and no control over the trail objects.

How can I keep track of the timers and obj, so I can cancel the timers with a scene change AND delete all the objects which are still there WITHOUT adding too much to the mem?

EDIT:

I think about doing the following: For each weapon I create a group like this:

weapon.objGroup=newGroup()

then I should be able to put all created bullets in the group.

newBullet=newImage…

weapon.objGroup:insert(newBullet)

Some get deleted, some will make it (life time) until the game scene is changing (for example to the main menu of the game). Then I should be able to cycle through all the still existing bullets by going through the groups children, right?

Is there a downside doing it like this to make sure I have removed all existing bullets in the scene before changing to another scene?