What is faster - many small enterFrame listeners or only one but large?

Hey everybody!

I have built some pretty complicated game logic and now I’m deeply in performance improving process.

My question is: in general should I try to avoid using many enterFrame runtime listeners even if it makes architecture more complicated?

Example:

Say I have two objects - a player and a ball. Player is moving so I set an event listener:

[lua]local function trackPlayer()

playerObj:translate(dx,dy)

end

Runtime:addEventListener(“enterFrame”, trackPlayer)

[/lua]

I want to know when the ball occurs behind player:

[lua]local function trackBall()

if(playerObj.x > ballObj.x) then

– something here

end

end

Runtime:addEventListener(“enterFrame”, trackBall)

[/lua]

In this example I could easily merge this two tracking functions into one. But in real project things are much complicated, there are many dynamically added objects trying to detect player position and do something. So programmatically it’s much easier to create new runtime enterFrame listener on each object but those listeners would be still pretty light and easy.

On the other hand I can implement some new algorithms to bring all those objects into one tracking function and that function will loop through my objects array and perform the same actions.

So whats faster?

Any help is appreciated, thank you!

Best regards,

Anton

Hi Anton,

This is a difficult question to answer. There are tradeoffs to each path, and I suppose it depends on exactly how complex your “one tracking function” would be. For example, if you’re just detecting 5 unique objects, then it’s probably OK to bundle them all into one function. However, if you’re adding in like 20-30 conditional statements in there, and on every frame it must detect which item it’s checking for, then it will probably be slower than just writing separate smaller handlers.

Another possible benefit to writing separate handlers is that you could “toggle” them on and off as needed… meaning, you could remove the Runtime listener entirely for an object that you didn’t care about at some point in the app, and then re-enable it later. For example, in a game I wrote sometime back, I had a Runtime listener for when the player would enter the range of an “air vent” so that I could apply constant force on the player. Naturally, this listener was pointless when the player was not in the range of a vent, so I just toggled it on and off as needed, depending on the location of the player to that particular vent (I used a physics sensor to detect this locational relationship).

Hope this helps,

Brent

Hi Brent,

thanks for your attention! It looks like you were right that this question is more about architecture than performance. I’ve been experimenting today and here is what I’ve got.

I’ve created pretty simple example with display object creation and moving. I tried to create 100 objects and move them by separate listener each. Then the same but only one listener with for loop.

For performance measure I used getDeltaTime() function that counts the time difference between current and previous frames. I tried it with both manyListeners() and oneListener(). I also tried to run program without any object creation and just to measure initial between-frame-time.

The code and the result chart are below:

[lua]local _runtime = 0

local function getDeltaTime()

   local temp = system.getTimer()

   local dt = system.getTimer() - _runtime

   _runtime = temp

   return dt

end

local math_random = math.random

local allObjects = {}

local function moveObj( o )

               o:translate(o.dx, o.k*o.dx+o. B)

end

local function createObject()

               local o = display.newImageRect(“obj.png”, 192, 178)

               o.x = display.contentCenterX

               o.y = display.contentCenterY

               o.k = math_random(-4,4)

               o.b = math_random(-10,10)

               o.dx = math_random(-2,2)

               function o:enterFrame(event)

                              moveObj(self)

               end

               return o

end

for i=1,100 do

               local o = createObject()

               allObjects[i] = o

end

local function manyListeners()

               for i=1,100 do

                              Runtime:addEventListener(“enterFrame”, allObjects[i])

               end

end

local function oneListener()

               local f = function(event)

                              for i=1,100 do

                                            moveObj(allObjects[i])

                              end

               end

               Runtime:addEventListener(“enterFrame”, f)

end

manyListeners()

– oneListener()

Runtime:addEventListener(“enterFrame”, function() print(getDeltaTime()) end)[/lua]

The charts are pretty equal in all 3 cases. Maybe there was not too much highload but as for me this result does look very promising!

Best regards,

Anton

Hi Anton,

This is a difficult question to answer. There are tradeoffs to each path, and I suppose it depends on exactly how complex your “one tracking function” would be. For example, if you’re just detecting 5 unique objects, then it’s probably OK to bundle them all into one function. However, if you’re adding in like 20-30 conditional statements in there, and on every frame it must detect which item it’s checking for, then it will probably be slower than just writing separate smaller handlers.

Another possible benefit to writing separate handlers is that you could “toggle” them on and off as needed… meaning, you could remove the Runtime listener entirely for an object that you didn’t care about at some point in the app, and then re-enable it later. For example, in a game I wrote sometime back, I had a Runtime listener for when the player would enter the range of an “air vent” so that I could apply constant force on the player. Naturally, this listener was pointless when the player was not in the range of a vent, so I just toggled it on and off as needed, depending on the location of the player to that particular vent (I used a physics sensor to detect this locational relationship).

Hope this helps,

Brent

Hi Brent,

thanks for your attention! It looks like you were right that this question is more about architecture than performance. I’ve been experimenting today and here is what I’ve got.

I’ve created pretty simple example with display object creation and moving. I tried to create 100 objects and move them by separate listener each. Then the same but only one listener with for loop.

For performance measure I used getDeltaTime() function that counts the time difference between current and previous frames. I tried it with both manyListeners() and oneListener(). I also tried to run program without any object creation and just to measure initial between-frame-time.

The code and the result chart are below:

[lua]local _runtime = 0

local function getDeltaTime()

   local temp = system.getTimer()

   local dt = system.getTimer() - _runtime

   _runtime = temp

   return dt

end

local math_random = math.random

local allObjects = {}

local function moveObj( o )

               o:translate(o.dx, o.k*o.dx+o. B)

end

local function createObject()

               local o = display.newImageRect(“obj.png”, 192, 178)

               o.x = display.contentCenterX

               o.y = display.contentCenterY

               o.k = math_random(-4,4)

               o.b = math_random(-10,10)

               o.dx = math_random(-2,2)

               function o:enterFrame(event)

                              moveObj(self)

               end

               return o

end

for i=1,100 do

               local o = createObject()

               allObjects[i] = o

end

local function manyListeners()

               for i=1,100 do

                              Runtime:addEventListener(“enterFrame”, allObjects[i])

               end

end

local function oneListener()

               local f = function(event)

                              for i=1,100 do

                                            moveObj(allObjects[i])

                              end

               end

               Runtime:addEventListener(“enterFrame”, f)

end

manyListeners()

– oneListener()

Runtime:addEventListener(“enterFrame”, function() print(getDeltaTime()) end)[/lua]

The charts are pretty equal in all 3 cases. Maybe there was not too much highload but as for me this result does look very promising!

Best regards,

Anton