Game lags when using event frame listener to track obstacle collisions

I’m making a simple endless runner type of game where the player has to dodge incoming obstacles. The spawning seems to work fine, everything seems to work fine…but I run into an issue when I had a enterframe listener to track the collision of the obstacles with the player. The game starts lagging a lot. I have a feeling this is due to some issue with not removing slots in the table where I’m containing the spawned obstacles. I feel like nothing I try seems to work, any help?

This is the event listener that seems to cause all of the problems (the game doesn’t lag unless this specific section is activated):

local function eventFramer(event) for i = 1, #spawnTable do if hasCollided( spawnTable[i], balloon ) then --branchTable[i]:removeSelf() --branchTable[i] = nil redRect:setFillColor(1,0,0) redRect.alpha = 0.7 transition.to(redRect,{time=300,alpha=0}) decreaseScore() end if hasCollided( spawnTable[i], topSide ) then print("branch removed") --spawnTable.remove(spawnTable[i]) spawnTable[i]:removeSelf() spawnTable[i] = nil end end return true end

I’m spawning the obstacles continuously using the exact method given in this guide: https://coronalabs.com/blog/2011/09/14/how-to-spawn-objects-the-right-way/.

 --Function to spawn an object local function spawn(params) local object = display.newImage(params.image) --Set the objects table to a table passed in by parameters object.objTable = params.objTable --Automatically set the table index to be inserted into the next available table index object.index = #object.objTable + 1 --Give the object a custom name object.myName = "Object : " .. object.index --If the object should have a body create it, else dont. if params.hasBody then --Allow physics parameters to be passed by parameters: object.density = params.density or 0 object.friction = params.friction or 0 object.bounce = params.bounce or 0 object.isSensor = params.isSensor or false object.bodyType = params.bodyType or "dynamic" physics.addBody(object, object.bodyType, {density = object.density, friction = object.friction, bounce = object.bounce, isSensor = object.isSensor}) end --The objects group object.group = params.group or nil --If the function call has a parameter named group then insert it into the specified group object.group:insert(object) --Insert the object into the table at the specified index object.objTable[object.index] = object return object end --Create a table to hold our spawns local spawnTable = {}

And I’m using the collision detection method described in this guide: http://omnigeek.robmiracle.com/2011/12/14/collision-detection-without-physics/

 local function hasCollided( obj1, obj2 ) if ( obj1 == nil ) then --make sure the first object exists return false end if ( obj2 == nil ) then --make sure the other object exists return false end local left = obj1.contentBounds.xMin \<= obj2.contentBounds.xMin and obj1.contentBounds.xMax \>= obj2.contentBounds.xMin local right = obj1.contentBounds.xMin \>= obj2.contentBounds.xMin and obj1.contentBounds.xMin \<= obj2.contentBounds.xMax local up = obj1.contentBounds.yMin \<= obj2.contentBounds.yMin and obj1.contentBounds.yMax \>= obj2.contentBounds.yMin local down = obj1.contentBounds.yMin \>= obj2.contentBounds.yMin and obj1.contentBounds.yMin \<= obj2.contentBounds.yMax return (left or right) and (up or down) end

Am I just removing objects from the table incorrectly or what?

Thank you.

That indexing scheme is error prone.  I’d do this instead (not tested for typos):

--Create a table to hold our spawns local spawnTable = {} local function hasCollided( obj1, obj2 ) if ( not obj1 or not obj2 ) then return false end local left = obj1.contentBounds.xMin \<= obj2.contentBounds.xMin and obj1.contentBounds.xMax \>= obj2.contentBounds.xMin local right = obj1.contentBounds.xMin \>= obj2.contentBounds.xMin and obj1.contentBounds.xMin \<= obj2.contentBounds.xMax local up = obj1.contentBounds.yMin \<= obj2.contentBounds.yMin and obj1.contentBounds.yMax \>= obj2.contentBounds.yMin local down = obj1.contentBounds.yMin \>= obj2.contentBounds.yMin and obj1.contentBounds.yMin \<= obj2.contentBounds.yMax return (left or right) and (up or down) end local function eventFramer( event) for k,v in pairs( spawnTable ) do if hasCollided( v, balloon ) then redRect:setFillColor(1,0,0) redRect.alpha = 0.7 transition.to(redRect,{time=300,alpha=0}) decreaseScore() end if hasCollided( v, topSide ) then print("branch removed") display.remove( v ) spawnTable[v] = nil end end return true end --Function to spawn an object local function spawn(params) local group = params.group or display.currentStage local object = display.newImage( group, params.image ) params.objTable[object] = object if params.hasBody then object.density = params.density or 0 object.friction = params.friction or 0 object.bounce = params.bounce or 0 object.isSensor = params.isSensor or false object.bodyType = params.bodyType or "dynamic" physics.addBody(object, object.bodyType, { density = object.density, friction = object.friction, bounce = object.bounce, isSensor = object.isSensor} ) end return object end

You use numeric indexing when you need speed, but it has a nasty side-effect.  It is easy to make ‘holes’ what the iterator (#) can’t handle.  Generally, I used keyed tables (as above) because they are simple and ‘hole-impervious’.

If you need to count the entries in the table, do this:

local function countTable( tbl ) local count = 0 for k,v in pairs(tbl) do count = count + 1 end return count end

agree wtih roaminggamer - a keyed table will be more convenient

Aside, take this for what it’s worth:

IMO, Corona does itself a bit of a dis-favor with blogs/articles that imply this is THE way to do something.

Also note that the rectangle-overlap test you’re using is inefficient – google it, it should only take 4 conditionals + 3 booleans.

The one you’re using has 8 conditionals + 7 booleans + 4 unnecessary local variables (and could also benefit from some aliasing/localizing, unnecessarily tests for missing objecty via equality with nil (there’s a more elegant equivalent syntax that could be “rolled into” a single-line return version of that function), etc).

The difference probably isn’t enough to worry about, but I’ve nitpicked it to again illustrate the problem with just accepting found code as “gospel” – even if it comes from Corona staff.

hth

Hey thanks for the advice. I changed it to the table-key format and performance noticeably improved. The lag takes a bit longer to start up, but lag it does nonetheless.

I’m thinking that this might have to do with my endless background scrolling. So when my character is falling (endlessly falling) in my game, the background scrolls up, with layers of clouds translating upwards.

I don’t want to dump the mass of code I did to figure out an endlessly scrolling background just yet (because it’s really ugly and messy), but I want to ask: right now, my endlessly scrolling background is just that, it’s being translated upwards, and the y axis is constantly increasing. I wonder if at a certain point this y axis becomes too large a number for the app to handle? Is this a thing? If so, what’s a better practice to resolve this issue?

Hi @exclaimteam,

As some long-time Corona community members know, I’m a big proponent of the physics engine in applicable apps. So, I’m very curious why you’re using the physics engine but not using it for collision detection. This seems counter-intuitive to me, so please provide your reasons for doing so and perhaps I can provide better advice.

Brent

@Brent Sorrentino,

Most likely due to just lack of experience. I played around with the physics engine, and I’m open to using it certainly. However, the way the app works right now is:

I have a character hanging from a balloon&string (you might remember this, I think you posted in response to some other questions I asked before). Physics is applied to the balloon/string/character. Obstacles fly upwards in the game (because the character is falling). Originally I had the obstacles fly upwards based on gravity, but was unhappy with how the objects would spawn, then quickly accelerate upwards. It looked like the object moved slowly at first, then quickly zipped up. I figured translating it using transition animations would look smoother, so that’s what I have right now. The obstacles fly up at a constant rate, but are no longer participating as physics objects, so this collision detector is what I have now.

Game looks like this (balloons obstacles are placeholder):

http://puu.sh/kDrGX/3058671679.png

edit- to clarify I want the game to have a rhythm about it, which is why it’s important to me to have obstacles move at a constant rate. With accelerating obstacles it looks really imbalanced and haphazard.

edit2 - I found out how to make physics objects move at a constant rate. Trying to do this using physics objects as obstacles…seems to be fixing the problem…

Hi @exclaimteam,

Yes, it sounds like you’re on the right track now. Just set the gravity to 0 and use “object:setLinearVelocity()” on the objects which are moving upward (to simulate the player is falling). Use standard collision detection for objects vs. player, collision filters if you want to prevent certain objects from colliding with other objects, etc.

Brent

Yep! What you said worked perfectly! Thanks so much.

That indexing scheme is error prone.  I’d do this instead (not tested for typos):

--Create a table to hold our spawns local spawnTable = {} local function hasCollided( obj1, obj2 ) if ( not obj1 or not obj2 ) then return false end local left = obj1.contentBounds.xMin \<= obj2.contentBounds.xMin and obj1.contentBounds.xMax \>= obj2.contentBounds.xMin local right = obj1.contentBounds.xMin \>= obj2.contentBounds.xMin and obj1.contentBounds.xMin \<= obj2.contentBounds.xMax local up = obj1.contentBounds.yMin \<= obj2.contentBounds.yMin and obj1.contentBounds.yMax \>= obj2.contentBounds.yMin local down = obj1.contentBounds.yMin \>= obj2.contentBounds.yMin and obj1.contentBounds.yMin \<= obj2.contentBounds.yMax return (left or right) and (up or down) end local function eventFramer( event) for k,v in pairs( spawnTable ) do if hasCollided( v, balloon ) then redRect:setFillColor(1,0,0) redRect.alpha = 0.7 transition.to(redRect,{time=300,alpha=0}) decreaseScore() end if hasCollided( v, topSide ) then print("branch removed") display.remove( v ) spawnTable[v] = nil end end return true end --Function to spawn an object local function spawn(params) local group = params.group or display.currentStage local object = display.newImage( group, params.image ) params.objTable[object] = object if params.hasBody then object.density = params.density or 0 object.friction = params.friction or 0 object.bounce = params.bounce or 0 object.isSensor = params.isSensor or false object.bodyType = params.bodyType or "dynamic" physics.addBody(object, object.bodyType, { density = object.density, friction = object.friction, bounce = object.bounce, isSensor = object.isSensor} ) end return object end

You use numeric indexing when you need speed, but it has a nasty side-effect.  It is easy to make ‘holes’ what the iterator (#) can’t handle.  Generally, I used keyed tables (as above) because they are simple and ‘hole-impervious’.

If you need to count the entries in the table, do this:

local function countTable( tbl ) local count = 0 for k,v in pairs(tbl) do count = count + 1 end return count end

agree wtih roaminggamer - a keyed table will be more convenient

Aside, take this for what it’s worth:

IMO, Corona does itself a bit of a dis-favor with blogs/articles that imply this is THE way to do something.

Also note that the rectangle-overlap test you’re using is inefficient – google it, it should only take 4 conditionals + 3 booleans.

The one you’re using has 8 conditionals + 7 booleans + 4 unnecessary local variables (and could also benefit from some aliasing/localizing, unnecessarily tests for missing objecty via equality with nil (there’s a more elegant equivalent syntax that could be “rolled into” a single-line return version of that function), etc).

The difference probably isn’t enough to worry about, but I’ve nitpicked it to again illustrate the problem with just accepting found code as “gospel” – even if it comes from Corona staff.

hth

Hey thanks for the advice. I changed it to the table-key format and performance noticeably improved. The lag takes a bit longer to start up, but lag it does nonetheless.

I’m thinking that this might have to do with my endless background scrolling. So when my character is falling (endlessly falling) in my game, the background scrolls up, with layers of clouds translating upwards.

I don’t want to dump the mass of code I did to figure out an endlessly scrolling background just yet (because it’s really ugly and messy), but I want to ask: right now, my endlessly scrolling background is just that, it’s being translated upwards, and the y axis is constantly increasing. I wonder if at a certain point this y axis becomes too large a number for the app to handle? Is this a thing? If so, what’s a better practice to resolve this issue?

Hi @exclaimteam,

As some long-time Corona community members know, I’m a big proponent of the physics engine in applicable apps. So, I’m very curious why you’re using the physics engine but not using it for collision detection. This seems counter-intuitive to me, so please provide your reasons for doing so and perhaps I can provide better advice.

Brent

@Brent Sorrentino,

Most likely due to just lack of experience. I played around with the physics engine, and I’m open to using it certainly. However, the way the app works right now is:

I have a character hanging from a balloon&string (you might remember this, I think you posted in response to some other questions I asked before). Physics is applied to the balloon/string/character. Obstacles fly upwards in the game (because the character is falling). Originally I had the obstacles fly upwards based on gravity, but was unhappy with how the objects would spawn, then quickly accelerate upwards. It looked like the object moved slowly at first, then quickly zipped up. I figured translating it using transition animations would look smoother, so that’s what I have right now. The obstacles fly up at a constant rate, but are no longer participating as physics objects, so this collision detector is what I have now.

Game looks like this (balloons obstacles are placeholder):

http://puu.sh/kDrGX/3058671679.png

edit- to clarify I want the game to have a rhythm about it, which is why it’s important to me to have obstacles move at a constant rate. With accelerating obstacles it looks really imbalanced and haphazard.

edit2 - I found out how to make physics objects move at a constant rate. Trying to do this using physics objects as obstacles…seems to be fixing the problem…

Hi @exclaimteam,

Yes, it sounds like you’re on the right track now. Just set the gravity to 0 and use “object:setLinearVelocity()” on the objects which are moving upward (to simulate the player is falling). Use standard collision detection for objects vs. player, collision filters if you want to prevent certain objects from colliding with other objects, etc.

Brent

Yep! What you said worked perfectly! Thanks so much.