removing display objects from memory without inserting in self.view

HI guys, I’m making a line just like fruit ninja effect when you touch the screen.

I have this effect in a module called lineDrawing.lua
I also have a file called level1.lua that has been setup with storyboard. In level1.lua I call the startListener() function from lineDrawing to start the fruitninja effect.

My problem is that my display.newLines from lineDrawing.lua never get released from memory even though I removed and nilled them because they are never inserted into the self.view group from level1.lua … I don’t want to insert the lineDrawing code on every level. Is there a correct way to release this memory and still have my lineDrawing module?

thanks a lot! :slight_smile:

[code]
–lineDrawing.lua
local LD ={}

local bx, by=0, 0 – Create our variables for drawing the line
local lines={}

local function fruitNinja(event)
if “began”==event.phase then
bx, by=event.x, event.y
elseif “moved”==event.phase then
for i=#lines+1, #lines+1 do
lines[i]=display.newLine(bx, by, event.x, event.y)
lines[i].width=10
local myLine=lines[i]

local function erase(obj)
display.remove(obj) – not sure if this is ok
obj=nil
end
lines[i].transition=transition.to(myLine, {alpha=0, width=1, time=300, onComplete=erase}) – The key transition
bx, by=event.x, event.y
end
elseif “ended”==event.phase then
end
end

local startListener = function()
Runtime:addEventListener(“touch”, fruitNinja)
end
LD.startListeners = startListeners

local removeListener = function ()
Runtime:removeEventListener(“touch”, fruitNinja)
end
LD.removeListeners = removeListeners

return LD

[/code] [import]uid: 74667 topic_id: 35817 reply_id: 335817[/import]

Hi @potsifera,
This is just thinking out loud, but how about passing a dedicated display group to the drawing module from your “level1.lua” when you start the listener function, and then all of your lines can be drawn to that group? Once in that group, you should be able to manage them easier, versus putting them in a “lines” table (by the way, it looks like your lines weren’t being freed from memory because you aren’t removing their reference from the lines table in the “erase” function).

This is a really quick test I worked up; should work but give it a test…

--linedraw.lua  
local LD = {}  
  
local putInGroup --up-reference to the dedicated display group  
  
local function erase( event )  
 display.remove( event ) ; event.trans = nil ; event = nil  
end  
  
local function drawDots( group )  
 local dot = display.newCircle( putInGroup,0,0,10 ) ; dot:setFillColor(255)  
 dot.x = math.random(0,300) ; dot.y = math.random(0,600)  
 dot.trans = transition.to( dot, {alpha=0.5, time=300, onComplete=erase })   
end  
  
local function startListener( myDisplayGroup )  
 Runtime:addEventListener("touch", drawDots)  
 putInGroup = myDisplayGroup  
end  
LD.startListener = startListener  
  
return LD  
--level1.lua  
local LD = require("linedraw")  
  
local myGroup = display.newGroup()  
LD.startListener( myGroup )  

Might this work for you?
Brent [import]uid: 200026 topic_id: 35817 reply_id: 142453[/import]

thanks so much Brent, I honestly never thought of such an elegant solution. just tried it and works perfect. thanks again :slight_smile: [import]uid: 74667 topic_id: 35817 reply_id: 142519[/import]

I feel like there’s some powerful mojo here, both in the question and the answer. I’ve been spending a lot of time working with storyboard and external modules and this seems very applicable to my efforts.

Am I understanding this correctly that the goal is to be able to reference the storyboard group in the module?

Brent, in your example I see that the myGroup group is passed and the putInGroup value gets set to that. I lose the example there though. How does putInGroup get utilized in the module?

Also, a question I’ve thought of looking at your example Brent. What would be the difference between these two ways of setting the LD.startListener value?:
[lua]
LD.startListener = startListener[/lua]or
[lua]
LD.startListener = startListener()
[/lua]

I’ve been using function brackets whenever I set a module table with a function and I’m wondering if I should be doing that without them the way that you have it in your sample?

Thanks :slight_smile: [import]uid: 105707 topic_id: 35817 reply_id: 143241[/import]

Hi @potsifera,
This is just thinking out loud, but how about passing a dedicated display group to the drawing module from your “level1.lua” when you start the listener function, and then all of your lines can be drawn to that group? Once in that group, you should be able to manage them easier, versus putting them in a “lines” table (by the way, it looks like your lines weren’t being freed from memory because you aren’t removing their reference from the lines table in the “erase” function).

This is a really quick test I worked up; should work but give it a test…

--linedraw.lua  
local LD = {}  
  
local putInGroup --up-reference to the dedicated display group  
  
local function erase( event )  
 display.remove( event ) ; event.trans = nil ; event = nil  
end  
  
local function drawDots( group )  
 local dot = display.newCircle( putInGroup,0,0,10 ) ; dot:setFillColor(255)  
 dot.x = math.random(0,300) ; dot.y = math.random(0,600)  
 dot.trans = transition.to( dot, {alpha=0.5, time=300, onComplete=erase })   
end  
  
local function startListener( myDisplayGroup )  
 Runtime:addEventListener("touch", drawDots)  
 putInGroup = myDisplayGroup  
end  
LD.startListener = startListener  
  
return LD  
--level1.lua  
local LD = require("linedraw")  
  
local myGroup = display.newGroup()  
LD.startListener( myGroup )  

Might this work for you?
Brent [import]uid: 200026 topic_id: 35817 reply_id: 142453[/import]

thanks so much Brent, I honestly never thought of such an elegant solution. just tried it and works perfect. thanks again :slight_smile: [import]uid: 74667 topic_id: 35817 reply_id: 142519[/import]

local function drawDots( group )  
 local dot = display.newCircle( putInGroup,0,0,10 ) ; dot:setFillColor(255)  
 dot.x = math.random(0,300) ; dot.y = math.random(0,600)  
 dot.trans = transition.to( dot, {alpha=0.5, time=300, onComplete=erase })   
end  

Why is it necessary to have “(group)” in this function? [import]uid: 73951 topic_id: 35817 reply_id: 143563[/import]

Hi Mort,
Looks like that’s a tiny error… that argument is not needed. I must have put it in there thinking I’d pass a group to the “drawDots” function directly, but in fact, I just start the touch event listener. :slight_smile:

Brent [import]uid: 200026 topic_id: 35817 reply_id: 143607[/import]

Small request: would you mind editing the code above to fix the tiny error? I’ve found that it’s helpful to people who may use this thread as a reference later on.
@EHO: See this thread for an explanation of the reference LD.startListener = startListener : http://www.coronalabs.com/blog/2011/09/05/a-better-approach-to-external-modules/ [import]uid: 73951 topic_id: 35817 reply_id: 143640[/import]

Hi mort, the edit is made. Thanks for pointing it out. [import]uid: 200026 topic_id: 35817 reply_id: 143643[/import]

@Brent So, is it safe to assume that if one removes MyGroup from within level1.lua, said generated objects passed through linedraw.lua will be freed from memory (excluding those already removed)?

[import]uid: 73951 topic_id: 35817 reply_id: 143670[/import]

Hi @mort,
When I tested this, the display objects added to “myGroup” are removed properly, and from memory. Of course, standard cleanup processes still apply, like canceling timers or transitions, removing them from any external “reference tables”, etc.

On that note, I just updated my code sample and took out the fade transition on the “dots”… mostly to make this clearer and not pollute this core process with an aspect that some people won’t need.

Brent [import]uid: 200026 topic_id: 35817 reply_id: 143774[/import]

Hi @mort,
With the modification, try putting some objects in the group (in “linedraw.lua”) and then, from “level1.lua”, remove the group… those objects should be deleted and memory cleared. If they’re not, let me know and I’ll test some things out memory-wise on my end.

Brent [import]uid: 200026 topic_id: 35817 reply_id: 143809[/import]

Great. Now, since auto-cleanup is gone (within linedraw.lua), how would one go about removing said lines using level1.lua?

My approach

  1. Passing group to linedraw.lua to capture created objects (We’ve done this, right?). ?

  2. Destroying said objects whilst in level1.lua. See where I’m going? I’d like to pass arguments through external modules for object creation, whilst managing the removal of objects from my original level module.


Think of the modules such as linedraw.lua as filters through which I run data.

Structure:
main.lua
|
level 1.lua level 2. lua …etc.
\ /

functions.lua, linedraw.lua (just to use the current example, I’m not actually drawing lines in my project), character.lua

Would it be just the removal of “myGroup” and would there be anything one must nil out? [import]uid: 73951 topic_id: 35817 reply_id: 143805[/import]

Yes, that’s the idea. I can test this later tonight to ensure the memory is clearing properly… [import]uid: 200026 topic_id: 35817 reply_id: 143814[/import]

Much appreciated, I’ll get back to you if I have any other concerns as well! Thanks again. I’m just trying to make a reliable template/structure for managing objects. I don’t like having duplicate code in every single one of my modules, too much room for error. Let me know if there are any concerns one may have when it comes to upvalues and external references that may impeded object cleanup. That’s another thing that’s bugging me. [import]uid: 73951 topic_id: 35817 reply_id: 143816[/import]

@Brent, correct me if I’m wrong, but aren’t the dots we created in module, linedraw already in the group “myGroup” in module, level1?

Would display.remove( myGroup ); myGroup = nil suffice in removing the drawn dots from memory?
EDIT: I meant display.remove … oops! [import]uid: 73951 topic_id: 35817 reply_id: 143812[/import]

Hi @mort,
I just tested out my module (from the original code) and the memory is clearing properly when the group is removed. I see you’re adding more functionality to it, like canceling the timers and such, and that’s fine.

I would suggest you localize your variables and functions though, i.e. myGroup, function “removeAll”, functions “ld.startListener” and “ld.endListener”, etc. I just stay away from global entirely now… I suppose some globals are OK, but I do everything within my power to avoid them.

If in doubt, you should try to just check your memory in the routine, and see how the numbers print out over time. This is the function I use:

local function garbagePrinting()  
 collectgarbage("collect")  
 local memUsage\_str = string.format( "MEMORY = %.3f KB", collectgarbage( "count" ) )  
 print( memUsage\_str, "TEXTURE = "..(system.getInfo("textureMemoryUsed")/1000000) )  
end  
timer.performWithDelay( 1000, garbagePrinting, 0 )  

Brent [import]uid: 200026 topic_id: 35817 reply_id: 143940[/import]

I thought the LD.startListener/LD.endListener, using my method, are localized into the table LD? [import]uid: 73951 topic_id: 35817 reply_id: 143963[/import]

Yes, you’re right… I just noticed how you declare them now. My mistake. :slight_smile: [import]uid: 200026 topic_id: 35817 reply_id: 143965[/import]