Saving system memory doing a lot of transitions?

I’m working on our new game and I want to get rid of the huge system memory usage by doing a lot of transition.to transitions in the game. Most of the calls look like this:

local trans=transition.to(obj[x],{time=2000,x=x1,y=y1,transition=easing.inOutQuad,onComplete=function() moveBack(obj[x]) end})

Doing this kind of transitions really are using a lot of system memory when they get started. This makes a huge peak when a lot of objects have to be moved on screen simultaneously.

I now wonder what is the best practice here doing this the “correct” way, so everything works fast while at the same time save system memory?

I already have reduced the transition count a little bit, but I still have to work with a lot of object movement and explosions and stuff I have to move around on screen.

UPDATE: I’m doing a lot of path transitions like (obj.path{time=1000,x1=45,y1=32}) … so maybe this is the performance killer here???

As we talked about in the other topic ( https://forums.coronalabs.com/topic/63754-repeating-function-call-code-question/ ) at first you should stop using anonymous functions. The same result as above can be achieved by the following:

local trans=transition.to(obj[x],{time=2000,x=x1,y=y1,transition=easing.inOutQuad,onComplete=moveBack})

As the transition object is used as the parameter when calling the onComplete function.

If you want continue using transition (opposed to using an enterFrame loop and doing all the calculation yourself) there’s not much more room for optimization. All you can do then is try to use s less tranition as possible and stop transitions, that are out of the screen and no longer needed.

Thx for the info. I knew we had discussed this a little bit in the other thread and the example above including an anonymous function was a bad one because I have already updated the code after your help, but I wanted to make sure using transitions is okay, or if there is a better way of doing transitions regarding performance and memory at the same time.

The thing I have to optimize is this: I have a lot of objects on screen and at one point on screen there is an explosion. I’m not using physics and now want to move the objects in the blast radius away from the explosion center. BUT they have to be moved not only away but also using the easing.outElastic movement.

So I have two transitions to make for each object… the first one moving to a new target point by the blast, and a second wobbling the object by using the easing.outElastic.

This seams like the transition.to is the best solution but I have to be sure so I don’t get into performance and (or) memory trouble here.

thx again for your help!

You can easily avoid creating all of those closures.

You are doing this:

-- Poor managment of scope and creates a new closure every time -- local function moveBack( ??? ) -- Not clear what the argument is end local trans=transition.to(obj[x],{time=2000, onComplete=function() moveBack(obj[x]) end})

When  you should do this:

local objs = {} local function moveBackX( self ) -- You can have different functions for different move backs self.x = self.x0 end -- Now you make no closures -- for i - 1, 10 do local obj = display.newCircle( 10, 10, 10 ) obj.x0 = obj.x obj.onComplete = moveBackX -- reference the move back function you need using 'onComplete' field objs[obj] = obj transition.to( obj, { time=2000, onComplete = obj } ) end

Additionally, you don’t need to store the transition handles if all you’re using them for is to do a one-time cancel of all transitions.  You can cancel all active transitions in one function call:

transition.cancel() -- stop all active transitions

Or, you can stop all transitions on an object like this:

transition.cancel( obj ) -- reference to object

Thx for the great help!

I have one question regarding the known objects:

Is it possible to get access to a table when I do this:

local moveBack = function (self)      -- Access to table??? end function ...      objectTable[3].onComplete=moveBack      transition.to(objectTable[3],{time=100,x=100,y=200,onComplete=objectTable[3]}) end

Can I access the table objectTable inside the moveBack function somehow or just the objectTable[3] element?

For now I’m attaching a reference to the table on each object in the table. Don’t know if this is the best solution.

One more thing I can’t figure out right now is how to access more than one function?

In the example I’m accessing the moveBack function by onComplete… but how can I access another function.

Example:

local objs = {} local function moveInAgain (self)      self.x = self.xIn end local function moveBackX( self ) -- You can have different functions for different move backs      self.x = self.x0      -- NEW:      transition.to( self, { time=2000, onComplete =???? } ) -- how can I access moveInAgain from here? end -- Now you make no closures -- for i - 1, 10 do      local obj = display.newCircle( 10, 10, 10 )      obj.x0 = obj.x      obj.onComplete = moveBackX -- reference the move back function you need using 'onComplete' field      obj.onComplete = ??? -- what do I have to do here to get access to moveInAgain function above???      objs[obj] = obj      transition.to( obj, { time=2000, onComplete = obj } ) end

I struggle here with using the code for more functions (see comments in code above please)

I tried something like onComplete2 = moveInAgain … but this is not allowed I guess :slight_smile:

local objs = {} -- This is visible anywhere below -- Foward declare functions local moveInAgain local moveBackX moveInAgain = function(self) self.x = self.xIn -- I added this to show you how (if you wanted) you could -- remove the object from the table and delete it --[[objs[self] = nil display.remove(self) --]] end moveBackX = function( self ) self.x = self.x0 self.xIn = self.x self.onComplete = moveInAgain transition.to( self, { time=2000, onComplete = self } ) end for i = 1, 10 do local obj = display.newCircle( 10, 10, 10 ) obj.x0 = obj.x obj.onComplete = moveBackX objs[obj] = obj transition.to( obj, { time=2000, onComplete = obj } ) end

Thank you! This helps a lot! :slight_smile:

One more thing: How can I use this kind of code for timers? Can I avoid closures somehow with timers when I have to do something like this:

local timeris=timer.performWithDelay (1000,function() startOtherFunc (value1,value2) end,100)

I would like to call other functions with some values but want to use a memory friendly way to do this. Is there a similar option for timers as it is for transitions?

UPDATE: I need timers to create a LOT of bullets in the game and memory seem to add up when using the timer code like this above. Is there a best way to use timers without loosing memory over time?

UPDATE2: For now I’m using the following code:

local myClosure = function() return shootAtEnemy(Weapon) end if Weapon.weapontimer then         timer.cancel(Weapon.weapontimer) end Weapon.weapontimer=performWithDelay(shootFrequency,myClosure,1)

Instead of always adding to a timerarray like this timerarray[#timerarray+1]=performWithDelay I’m using the image itself to store the timer like this Weapon.weapontimer=performWithDelay … this way I’m only creating one timer for each image and reuse it if it is needed for a new bullet.

For closures I’m using a local now which seems to help also.

Seems to work… but is it the best solution?

Hey c.noeth,

well there’s a pretty easy way for passing timer parameters and it’s mentioned in the docs:

https://docs.coronalabs.com/api/library/timer/performWithDelay.html

Scroll down to the bottom of the page to the point “passing parameters 2”.

I’m also not sure, why you are using a return in your local function. The timer doesn’t care if you return a value in your function or not.

So, you can try something like this:

local shootWeaponClosure = function(event) local params = event.source.params local weapon = params.weapon shootAtEnemy(weapon) weapon.weapontimer = nil end if Weapon.weapontimer then timer.cancel(Weapon.weapontimer)end Weapon.weapontimer = performWithDelay(shootFrequency, shootWeaponClosure, 1) Weapon.weapontimer.params = {weapon = Weapon}

This also eliminates the timer warning “problem” you discribed in your other topic (https://forums.coronalabs.com/topic/64507-timer-warning-a-problem/) if you check for the existence of the timer before pausing it.

If you know you would only have one parameter (e.g. the weapon) you can also go for not using a param table at all:

local shootWeaponClosure = function(event) local weapon = event.source.params shootAtEnemy(weapon) weapon.weapontimer = nil end if Weapon.weapontimer then timer.cancel(Weapon.weapontimer)end Weapon.weapontimer = performWithDelay(shootFrequency, shootWeaponClosure, 1) Weapon.weapontimer.params = Weapon

Hope that helps :slight_smile:

Awesome!!! :slight_smile: Thank you!

As we talked about in the other topic ( https://forums.coronalabs.com/topic/63754-repeating-function-call-code-question/ ) at first you should stop using anonymous functions. The same result as above can be achieved by the following:

local trans=transition.to(obj[x],{time=2000,x=x1,y=y1,transition=easing.inOutQuad,onComplete=moveBack})

As the transition object is used as the parameter when calling the onComplete function.

If you want continue using transition (opposed to using an enterFrame loop and doing all the calculation yourself) there’s not much more room for optimization. All you can do then is try to use s less tranition as possible and stop transitions, that are out of the screen and no longer needed.

Thx for the info. I knew we had discussed this a little bit in the other thread and the example above including an anonymous function was a bad one because I have already updated the code after your help, but I wanted to make sure using transitions is okay, or if there is a better way of doing transitions regarding performance and memory at the same time.

The thing I have to optimize is this: I have a lot of objects on screen and at one point on screen there is an explosion. I’m not using physics and now want to move the objects in the blast radius away from the explosion center. BUT they have to be moved not only away but also using the easing.outElastic movement.

So I have two transitions to make for each object… the first one moving to a new target point by the blast, and a second wobbling the object by using the easing.outElastic.

This seams like the transition.to is the best solution but I have to be sure so I don’t get into performance and (or) memory trouble here.

thx again for your help!

You can easily avoid creating all of those closures.

You are doing this:

-- Poor managment of scope and creates a new closure every time -- local function moveBack( ??? ) -- Not clear what the argument is end local trans=transition.to(obj[x],{time=2000, onComplete=function() moveBack(obj[x]) end})

When  you should do this:

local objs = {} local function moveBackX( self ) -- You can have different functions for different move backs self.x = self.x0 end -- Now you make no closures -- for i - 1, 10 do local obj = display.newCircle( 10, 10, 10 ) obj.x0 = obj.x obj.onComplete = moveBackX -- reference the move back function you need using 'onComplete' field objs[obj] = obj transition.to( obj, { time=2000, onComplete = obj } ) end

Additionally, you don’t need to store the transition handles if all you’re using them for is to do a one-time cancel of all transitions.  You can cancel all active transitions in one function call:

transition.cancel() -- stop all active transitions

Or, you can stop all transitions on an object like this:

transition.cancel( obj ) -- reference to object

Thx for the great help!

I have one question regarding the known objects:

Is it possible to get access to a table when I do this:

local moveBack = function (self)      -- Access to table??? end function ...      objectTable[3].onComplete=moveBack      transition.to(objectTable[3],{time=100,x=100,y=200,onComplete=objectTable[3]}) end

Can I access the table objectTable inside the moveBack function somehow or just the objectTable[3] element?

For now I’m attaching a reference to the table on each object in the table. Don’t know if this is the best solution.

One more thing I can’t figure out right now is how to access more than one function?

In the example I’m accessing the moveBack function by onComplete… but how can I access another function.

Example:

local objs = {} local function moveInAgain (self)      self.x = self.xIn end local function moveBackX( self ) -- You can have different functions for different move backs      self.x = self.x0      -- NEW:      transition.to( self, { time=2000, onComplete =???? } ) -- how can I access moveInAgain from here? end -- Now you make no closures -- for i - 1, 10 do      local obj = display.newCircle( 10, 10, 10 )      obj.x0 = obj.x      obj.onComplete = moveBackX -- reference the move back function you need using 'onComplete' field      obj.onComplete = ??? -- what do I have to do here to get access to moveInAgain function above???      objs[obj] = obj      transition.to( obj, { time=2000, onComplete = obj } ) end

I struggle here with using the code for more functions (see comments in code above please)

I tried something like onComplete2 = moveInAgain … but this is not allowed I guess :slight_smile:

local objs = {} -- This is visible anywhere below -- Foward declare functions local moveInAgain local moveBackX moveInAgain = function(self) self.x = self.xIn -- I added this to show you how (if you wanted) you could -- remove the object from the table and delete it --[[objs[self] = nil display.remove(self) --]] end moveBackX = function( self ) self.x = self.x0 self.xIn = self.x self.onComplete = moveInAgain transition.to( self, { time=2000, onComplete = self } ) end for i = 1, 10 do local obj = display.newCircle( 10, 10, 10 ) obj.x0 = obj.x obj.onComplete = moveBackX objs[obj] = obj transition.to( obj, { time=2000, onComplete = obj } ) end

Thank you! This helps a lot! :slight_smile:

One more thing: How can I use this kind of code for timers? Can I avoid closures somehow with timers when I have to do something like this:

local timeris=timer.performWithDelay (1000,function() startOtherFunc (value1,value2) end,100)

I would like to call other functions with some values but want to use a memory friendly way to do this. Is there a similar option for timers as it is for transitions?

UPDATE: I need timers to create a LOT of bullets in the game and memory seem to add up when using the timer code like this above. Is there a best way to use timers without loosing memory over time?

UPDATE2: For now I’m using the following code:

local myClosure = function() return shootAtEnemy(Weapon) end if Weapon.weapontimer then         timer.cancel(Weapon.weapontimer) end Weapon.weapontimer=performWithDelay(shootFrequency,myClosure,1)

Instead of always adding to a timerarray like this timerarray[#timerarray+1]=performWithDelay I’m using the image itself to store the timer like this Weapon.weapontimer=performWithDelay … this way I’m only creating one timer for each image and reuse it if it is needed for a new bullet.

For closures I’m using a local now which seems to help also.

Seems to work… but is it the best solution?

Hey c.noeth,

well there’s a pretty easy way for passing timer parameters and it’s mentioned in the docs:

https://docs.coronalabs.com/api/library/timer/performWithDelay.html

Scroll down to the bottom of the page to the point “passing parameters 2”.

I’m also not sure, why you are using a return in your local function. The timer doesn’t care if you return a value in your function or not.

So, you can try something like this:

local shootWeaponClosure = function(event) local params = event.source.params local weapon = params.weapon shootAtEnemy(weapon) weapon.weapontimer = nil end if Weapon.weapontimer then timer.cancel(Weapon.weapontimer)end Weapon.weapontimer = performWithDelay(shootFrequency, shootWeaponClosure, 1) Weapon.weapontimer.params = {weapon = Weapon}

This also eliminates the timer warning “problem” you discribed in your other topic (https://forums.coronalabs.com/topic/64507-timer-warning-a-problem/) if you check for the existence of the timer before pausing it.

If you know you would only have one parameter (e.g. the weapon) you can also go for not using a param table at all:

local shootWeaponClosure = function(event) local weapon = event.source.params shootAtEnemy(weapon) weapon.weapontimer = nil end if Weapon.weapontimer then timer.cancel(Weapon.weapontimer)end Weapon.weapontimer = performWithDelay(shootFrequency, shootWeaponClosure, 1) Weapon.weapontimer.params = Weapon

Hope that helps :slight_smile: