Cannot check for collision after creating an object on the fly

Hey,

When my app loads I am spawning a player and an opponent. Whenever the player collides with the opponent I want to create a new opponent. The first and second opponent are created but there is no collision-detection on the second opponent. What am I doing wrong?

local function onCollision( event ) if ( event.phase == "began" and event.other.type == "opp" ) then spawnOpp()   elseif ( event.phase == "ended") then

 display.remove( event.other )     event.other = nil 

 end end player:addEventListener( "collision", onCollision ) spawnOpp = function () local opp = display.newRect( w/2, h, w, padding/2 ) physics.addBody( opp, "dynamic", {density = 0, bounce=0} ) opp.y = startHeight opp.type = "opp" opp:setFillColor(unpack(color.white)) opp.isSensor = true opp.isVisible = true opp.gravityScale = 0 end spawnOpp()

You shouldn’t create/modify/remove physics objects during a collision event, or weird things will happen.

See http://docs.coronalabs.com/api/event/collision/index.html

The workaround is to spawn the enemy outside the event, e.g. replace the line “spawnOpp()” with

timer.performWithDelay(1, spawnOpp)

This is such an amazing community. Thank you so much _memo!!  :slight_smile:

To piggy-back on _memo’s answer, it can negatively impact performance to spawn physics bodies on the fly. You might be better off generating all of your bodies ahead of time (at the start of the game/stage/level), placing them off-screen, and then placing them on-screen in your collision’s x/y location. 

Something like this:

-- before the game is actually started: local opp = {} local gF = 20 local function onCollision( event ) if ( event.phase == "began" and event.other.type == "opp" ) then event.other.x = event.x event.other.y = event.y elseif ( event.phase == "ended") then display.remove( event.other ) event.other = nil end end local function spawnOpp() for a=1, gF do opp[a] = display.newRect( w/2, h, w, padding/2 ) physics.addBody( opp[a], "dynamic", {density = 0, bounce=0} ) opp[a].y = startHeight opp[a].type = "opp" opp[a].num = "opp"..a opp[a]:setFillColor(unpack(color.white)) opp[a].isSensor = true opp[a].isVisible = true opp[a].gravityScale = 0 end end spawnOpp() -- collision listener (as normal): player:addEventListener( "collision", onCollision )

This gives you a bit more control over your spawned enemies, as they are now in a table and can be accessed with greater clarity from within your game. 

YMMV HTH

Thank you Alex@PaNc for your reply!

I was actually thinking about that as well but the problem is that I am dealing with an endless runner and I would probably have to generate around 500 objects in advance. I thought that would’t be good in regards of memory-usage. 

Thinking about it in terms of efficiency, you most likely won’t have all 500 enemy objects on-screen at one time. Assuming that’s the case (not saying it is) you can just move dead/defeated ones off-screen and then move them back on-screen when needed. That way you’re not constantly creating and deleting enemies, but just updating their positions and whether they are “alive” or “dead”.

Yes, that is actually a beautiful solution too. I could just hide and move the enemy. 

Thank you so much!

You shouldn’t create/modify/remove physics objects during a collision event, or weird things will happen.

See http://docs.coronalabs.com/api/event/collision/index.html

The workaround is to spawn the enemy outside the event, e.g. replace the line “spawnOpp()” with

timer.performWithDelay(1, spawnOpp)

This is such an amazing community. Thank you so much _memo!!  :slight_smile:

To piggy-back on _memo’s answer, it can negatively impact performance to spawn physics bodies on the fly. You might be better off generating all of your bodies ahead of time (at the start of the game/stage/level), placing them off-screen, and then placing them on-screen in your collision’s x/y location. 

Something like this:

-- before the game is actually started: local opp = {} local gF = 20 local function onCollision( event ) if ( event.phase == "began" and event.other.type == "opp" ) then event.other.x = event.x event.other.y = event.y elseif ( event.phase == "ended") then display.remove( event.other ) event.other = nil end end local function spawnOpp() for a=1, gF do opp[a] = display.newRect( w/2, h, w, padding/2 ) physics.addBody( opp[a], "dynamic", {density = 0, bounce=0} ) opp[a].y = startHeight opp[a].type = "opp" opp[a].num = "opp"..a opp[a]:setFillColor(unpack(color.white)) opp[a].isSensor = true opp[a].isVisible = true opp[a].gravityScale = 0 end end spawnOpp() -- collision listener (as normal): player:addEventListener( "collision", onCollision )

This gives you a bit more control over your spawned enemies, as they are now in a table and can be accessed with greater clarity from within your game. 

YMMV HTH

Thank you Alex@PaNc for your reply!

I was actually thinking about that as well but the problem is that I am dealing with an endless runner and I would probably have to generate around 500 objects in advance. I thought that would’t be good in regards of memory-usage. 

Thinking about it in terms of efficiency, you most likely won’t have all 500 enemy objects on-screen at one time. Assuming that’s the case (not saying it is) you can just move dead/defeated ones off-screen and then move them back on-screen when needed. That way you’re not constantly creating and deleting enemies, but just updating their positions and whether they are “alive” or “dead”.

Yes, that is actually a beautiful solution too. I could just hide and move the enemy. 

Thank you so much!