Collision Event Not Firing

So, I’m having an interesting problem with collision listeners. I have several instances of these listeners in my game code (one for each of 4 different types of enemies).  

They work fine the first time I go in to play the level.  But if I restart the level, or even exit to main menu and return back to the same level, the collision listeners aren’t activating.  I’ve verified that all iterations of the enemies are being destroyed upon exit of the scene.  My understanding is that the collision listeners should be destroyed with them.  

Is there, perhaps, a better method of activating the collision listeners that will possible fix this problem?

[lua]

local levelObjectsFront = display.newGroup() local enemyTable = {} local k = 1 local function createEnemySkulls() for i = 1, #levelLoad.enemyLoad do local skullLayout = { width = 75, height = 75, numFrames = 15, sheetContentWidth = 375, sheetContentHeight = 225, } local skullSheet = graphics.newImageSheet( "images/skullSprite.png", skullLayout ) local skullSequence = { {name="fly", start=1, count=3, time = 500, loopCount = 0 }, {name="attack", start=6, count=5, time = 500, loopCount = 1 }, {name="die", start=11, count=4, time = 500, loopCount = 1 }, } --print("amount = "..levelLoad.enemyLoad[i].amount) for x = 1, levelLoad.enemyLoad[i].amount do local skull = display.newSprite( skullSheet, skullSequence ) skull.x = levelLoad.enemyLoad[i].x -- -3780 skull.y = levelLoad.enemyLoad[i].y -- -1625 skull:setSequence("fly") skull:play() skull.anchorX = .5 skull.anchorY = .5 skull.objType = levelLoad.enemyLoad[i].objType skull.alpha = levelLoad.enemyLoad[i].alpha skull.rotation = levelLoad.enemyLoad[i].rotation physics.addBody(skull, "static", {density=2, bounce=3, friction=3, radius=20, isSensor=true}) levelObjectsFront:insert(skull) table.insert(enemyTable, k, {enemy=skull, x=levelLoad.enemyLoad[i].x, y=levelLoad.enemyLoad[i].y, xMax=levelLoad.enemyLoad[i].xMax, yMax=levelLoad.enemyLoad[i].yMax}) k = k + 1 local function skullTouch(self, event) local mySource = audio.getSourceFromChannel(1) local slowMusic = true if (event.phase == "began") then if (event.selfElement == 1 and event.other.objType == "carBody") or (event.selfElement == 1 and event.other.objType == "backWheel") or (event.selfElement == 1 and event.other.objType == "frontWheel") then globals.skullSoundChannel = audio.play(globals.skullSound, { channel=22 } ) self.alpha = .5 if globals.silverArrowCollected == true then local function destroyEnemy() dropCoinFunction(self.x, self.y) display.remove(self) self=nil end self:setSequence("die") self:play() globals.skullSoundChannel = audio.play(globals.skullSound, { channel=22 } ) globals.gameTimers[#globals.gameTimers+1] = timer.performWithDelay(500, destroyEnemy) else local skullDamage = 16 if globals.ghostBossLevel == 1 then skullDamage = 16 elseif globals.ghostBossLevel == 2 then skullDamage = 24 elseif globals.ghostBossLevel == 3 then skullDamage = 32 end if globals.redWheelCollected == true then skullDamage = skullDamage \* .5 end if globals.carContact == false then event.contact.bounce = 5 globals.carContact = true --Take coins from player if globals.coinsCollected \> skullDamage then --Do Slow the music slowMusic = true --Slow down car backWheel.angularDamping = 50 frontWheel.angularDamping = 50 bodyGroup.angularDamping = 300 backWheel.linearDamping = 8 frontWheel.linearDamping = 8 bodyGroup.linearDamping = 8 globals.coinsCollected = globals.coinsCollected - skullDamage --Display coins taken this time affectCoinsFunction("-"..skullDamage, self.x, self.y-50) --Update coin total display text coinStatus.text = "Coins: "..globals.coinsCollected else --Don't slow the music slowMusic = false --Display coins taken this time affectCoinsFunction("-"..tostring(globals.coinsCollected), self.x, self.y-50) --Take coins to 0 globals.coinsCollected = 0 --Update coin total display text coinStatus.text = "Coins: "..globals.coinsCollected --Send to start globals.gameIsActive = 0 globals.gameTimers[#globals.gameTimers+1] = timer.performWithDelay(1, teleportToStart) end if globals.currentLevel == 9 and slowMusic == true then local function slowMusic() globals.audioSlowDown = true local i = 1 local function pitchDown() if i \< 7 then local newPitch = 1 - (i \* .1) al.Source( mySource, al.PITCH, newPitch ) i = i + 1 globals.gameTimers[#globals.gameTimers+1] = timer.performWithDelay(10, pitchDown) end end pitchDown() end slowMusic() end end end end elseif (event.phase == "ended") then if (event.selfElement == 1 and event.other.objType == "backWheel") or (event.selfElement == 1 and event.other.objType == "frontWheel") then if globals.carContact == true then local function delayEnemyContact() globals.carContact = false end globals.gameTimers[#globals.gameTimers+1] = timer.performWithDelay(500, delayEnemyContact) local function delayNorms() backWheel.angularDamping = 20 frontWheel.angularDamping = 20 bodyGroup.angularDamping = 100 backWheel.linearDamping = .75 frontWheel.linearDamping = .75 bodyGroup.linearDamping = .75 self.alpha = 1 if globals.currentLevel == 9 and slowMusic == true then local function normMusic() local i = 5 local function pitchUp() if i \< 11 then local newPitch = (i \* .1) al.Source( mySource, al.PITCH, newPitch ) i = i + 1 globals.gameTimers[#globals.gameTimers+1] = timer.performWithDelay(10, pitchUp) end end pitchUp() end if globals.audioSlowDown == true then globals.audioSlowDown = false normMusic() end end end globals.gameTimers[#globals.gameTimers+1] = timer.performWithDelay(1500, delayNorms) else local function delayEnemyContact2() globals.carContact = false end globals.gameTimers[#globals.gameTimers+1] = timer.performWithDelay(500, delayEnemyContact2) end end end return true end skull.collision = skullTouch skull:addEventListener( "collision", skull ) end --end for loop for enemy skull end --end for loop for enemyLoad end --end create enemy skull function createEnemySkulls() sceneGroup:insert(levelObjectsFront)

[/lua]

I don’t know specifically why you’re seeing this problem - though I suspect it is related to not removing objects from the scene properly. I can however say that this is wrong:

 skull.collision = skullTouch skull:addEventListener( "collision", skull )

It should be

 skull.collision = skullTouch skull:addEventListener( "collision" )

Or

 skull:addEventListener( "collision", skullTouch )

I know that doesn’t seem likely, but I recently had something go wrong because of that sort of code, so it’s worth a try.

Also, make sure you are removing everything properly. Be careful about what you are adding listeners to. If the skulls are not being removed properly you could be adding listeners to objects which are not visible any more but are still there.

Thanks for the reply horacebury. I’ll try out that change tonight. As far as removing them goes, I am removing/nilling everything I put into the enemyTable in a for loop at scene:hide. Also, since they are local and placed into the scenegroup, shouldn’t their collision listeners be destroyed with the scene anyways?

I made the change you suggested and it didn’t change the behavior as you suspected.  I’ll troubleshoot it more later tonight.  Any other input would be greatly appreciated.

Can you boil the code down to demonstrate the same problem, but without all the other code?

Hi @kthompson200,

You may be removing enemies and so forth (on scene exit/restart), but where is your actual function for responding to collisions located within your scene framework (I assume Composer)? This description of “it works first time but not when I revisit the scene” sounds very likely to be a scope issue in how you’ve placed your listener function for collisions.

Brent

Thanks for the replies guys. I’ll boil the code down… should have done that on the original post. I have the listeners in Composer in scene:create.

I suspect that’s the issue… I would scope your collision listener above and outside any “scene:” functions… those are typically meant to handle things which, well, fit into their respective descriptions. :slight_smile:

Brent

Brent,

That’s interesting.  I didn’t realize that collision listeners should remain outside composer.  I’ve been doing a lot wrong in regards to that then.  If that’s the case, how will composer dispose of the listeners?

I was able to fix the problem before I read your most recent response.  I fixed it by changing the listener to the car instead of the enemies.  The car already has a collision listener with quite a few if statements, so I just inserted all the enemy functions into that listener in their own if statements.   Strange thing is that the car collision listener is also inside of scene:create.  Other than the enemies being created inside a for loop and there only being one car, there’s really not much else different.  So I don’t understand why one works and the other doesn’t.  Any thoughts???

Oh, I meant more that the listener function for your collisions should be scoped above/outside of the “scene:” functions. That just helps ensure that, as long as the scene object remains in memory, objects in the scene will have a reference to it.

That’s pretty much a good rule across all aspects of using Composer: functions which you want objects in your scene to call/reference, despite what “phase” of the scene’s life they exist in, should be scoped outside of the “scene:” functions.

Brent

I don’t know specifically why you’re seeing this problem - though I suspect it is related to not removing objects from the scene properly. I can however say that this is wrong:

 skull.collision = skullTouch skull:addEventListener( "collision", skull )

It should be

 skull.collision = skullTouch skull:addEventListener( "collision" )

Or

 skull:addEventListener( "collision", skullTouch )

I know that doesn’t seem likely, but I recently had something go wrong because of that sort of code, so it’s worth a try.

Also, make sure you are removing everything properly. Be careful about what you are adding listeners to. If the skulls are not being removed properly you could be adding listeners to objects which are not visible any more but are still there.

Thanks for the reply horacebury. I’ll try out that change tonight. As far as removing them goes, I am removing/nilling everything I put into the enemyTable in a for loop at scene:hide. Also, since they are local and placed into the scenegroup, shouldn’t their collision listeners be destroyed with the scene anyways?

I made the change you suggested and it didn’t change the behavior as you suspected.  I’ll troubleshoot it more later tonight.  Any other input would be greatly appreciated.

Can you boil the code down to demonstrate the same problem, but without all the other code?

Hi @kthompson200,

You may be removing enemies and so forth (on scene exit/restart), but where is your actual function for responding to collisions located within your scene framework (I assume Composer)? This description of “it works first time but not when I revisit the scene” sounds very likely to be a scope issue in how you’ve placed your listener function for collisions.

Brent

Thanks for the replies guys. I’ll boil the code down… should have done that on the original post. I have the listeners in Composer in scene:create.

I suspect that’s the issue… I would scope your collision listener above and outside any “scene:” functions… those are typically meant to handle things which, well, fit into their respective descriptions. :slight_smile:

Brent

Brent,

That’s interesting.  I didn’t realize that collision listeners should remain outside composer.  I’ve been doing a lot wrong in regards to that then.  If that’s the case, how will composer dispose of the listeners?

I was able to fix the problem before I read your most recent response.  I fixed it by changing the listener to the car instead of the enemies.  The car already has a collision listener with quite a few if statements, so I just inserted all the enemy functions into that listener in their own if statements.   Strange thing is that the car collision listener is also inside of scene:create.  Other than the enemies being created inside a for loop and there only being one car, there’s really not much else different.  So I don’t understand why one works and the other doesn’t.  Any thoughts???

Oh, I meant more that the listener function for your collisions should be scoped above/outside of the “scene:” functions. That just helps ensure that, as long as the scene object remains in memory, objects in the scene will have a reference to it.

That’s pretty much a good rule across all aspects of using Composer: functions which you want objects in your scene to call/reference, despite what “phase” of the scene’s life they exist in, should be scoped outside of the “scene:” functions.

Brent