Chapter 3 - Error in with onCollision not being called.

Hi all! (again)

I am having a bug appear with my collision logic. When an asteroid collides with the ship for the _first _time the game performs correctly (lives decrements and the ship disappears), but after that the ‘onCollision’ function is not called when the ship and asteroid collide for a second time. 

I’m not sure if there is something wrong with my event listener? I have added print() statements so I know for sure that the error is that the ‘onCollision’ function is not called for a second (and third etc) time. 

Here is my function: 

[lua]

local function onCollision( event )

     print(“onCollision called”)

     if (event.phase == “began”) then

          local obj1 = event.object1

          local obj2 = event.object2

          – Handle the laser / asteroid collision

          if ( (obj1.myName == “laser” and obj2.myName == “asteroid”) or

               (obj1.myName == “asteroid” and obj2.myName == “laser”) )

          then

               – Remove both the laser and asteroid

               display.remove(obj1)

               display.remove(obj2)

               for i = #asteroidsTable, 1, -1 do

                    if (asteroidsTable[i] == obj1 or asteroidsTable[i] == obj2) then

                         table.remove(asteroidsTable, i)

                         break

                    end

               end

               – Increase score

               score = score + 100

               scoreText.text = "Score: " … score

          – Handle the ship / asteroid collision

          elseif (  (obj1.myName == “ship” and obj2.myName == “asteroid”) or

                    (obj1.myName == “asteroid” and obj2.myName == “ship”) )

          then

               print(“inside death loop”)

               if (died == false) then

                    died = true

                    – Update lives

                    lives = lives - 1

                    livesText.text = "Lives: " … lives

                    if (lives == 0) then

                         display.remove(ship)

                    else

                         ship.alpha = 0

                         timer.performWithDelay( 1000, restoreShip )

                    end

               end

          end

     end

end

Runtime:addEventListener(“collision”, onCollision)

[/lua]

Thanks!

How does restoreShip function look like?

local function restoreShip()     ship.isBodyActive = false     ship:setLinearVelocity( 0, 0 )     ship.x = display.contentCenterX     ship.y = display.contentHeight - 100     -- Fade in the ship     transition.to( ship, { alpha=1, time=4000,         onComplete = function()             ship.isBodyActive = true             died = false         end     } ) end

I think my restoreShip() function is exactly the same?

[lua]

– Function to restore ship after death

local function restoreShip()

     – set body active to false so it does not interact with asteroids on fade-in

     ship.isBodyActive = false

     – Position and set the velocity of the ship

     ship:setLinearVelocity(0, 0)

     ship.x = display.contentCenterX

     ship.y = display.contentHeight-100

     – Fade in the ship

     – Alpha 0->1, 4000ms, onComplete turn body active, set died to false

     transition.to(ship, {alpha=1, time=4000,

          onComplete = function()

               ship.isBodayActive = true

               died = false

               print(“set died to false”)

          end

     })

end

[/lua]

Does collision between laser and asteroids also not work?

Thats the weird thing, the laser/asteroid collision is working perfectly as is the asteroid/asteroid collisions. Shooting an asteroid with the laser increments my score and both the objects disappear. 

I’m going to copy/paste my entire code below if that helps

[lua]


– main.lua

– Title:           Star Explorer - a space shooter game.

– Description:     Maneuver your starship through an asteroid field, destroying

–                  asteroids as you progress.

– Controls:        Tap on ship to fire. Drag to move left/right.

– Sounds:          Shooting/explosion sounds.

– Source:          https://docs.coronalabs.com/guide/programming/02/index.html


– Include physics (space so gravity = (0, 0))

local physics = require(“physics”)

physics.start()

physics.setGravity( 0, 0 )

– Seed the random number generator

math.randomseed(os.time())

– Load the image sheets

local sheetOptions =

{

     frames =

     {

          {    --1 Asteroid 1

               x = 0,

               y = 0,

               width = 102,

               height = 85

          },

          {    --2 Asteroid 2

               x = 0,

               y = 85,

               width = 90,

               height = 83

          },

          {    --3 Asteroid 3

               x = 0,

               y = 168,

               width = 100,

               height = 97

          },

          {    --4 Ship

               x = 0,

               y = 265,

               width = 98,

               height = 79

          },

          {    --5 Laser

               x = 98,

               y = 265,

               width = 14,

               height = 40

          },

     }

}

local objectSheet = graphics.newImageSheet( “gameObjects.png”, sheetOptions )

– Initialize variables

local lives = 3

local score = 0

local died = false

– Empty table initialized

local asteroidsTable = {}

local ship

local gameLoopTimer

local livesText

local scoreText

– Set up display groups

local backGroup = display.newGroup()    – Display group for background image

local mainGroup = display.newGroup()    – Display group for the main images (ships, asteroids)

local uiGroup = display.newGroup()      – Display group for the user interface

– Load the background

local background = display.newImageRect( backGroup, “background.png”, 800, 1400 )

background.x = display.contentCenterX

background.y = display.contentCenterY

– Load the ship

ship = display.newImageRect( mainGroup, objectSheet, 4, 98, 79 )

ship.x = display.contentCenterX

ship.y = display.contentHeight-100

physics.addBody(ship, {radius=30, isSensor=true})

ship.myName = “ship”

– Load the UI

livesText = display.newText(uiGroup, "Lives: " … lives, 200, 80, native.systemFont, 36)

scoreText = display.newText( uiGroup, "Score: " … score, 400, 80, native.systemFont, 36 )

– Hide the status bar

display.setStatusBar( display.HiddenStatusBar )

– Function to update text

local function updateText()

     livesText.text = "Lives: " … lives

     scoreText.text = "Score: " … score

end

– Function to create asteroids

local function createAsteroid()

     local newAsteroid = display.newImageRect(mainGroup, objectSheet, 1, 102, 85)

     – To keep track of the asteroids insert into a table

     table.insert(asteroidsTable, newAsteroid)

     physics.addBody( newAsteroid, “dynamic”, {radius=40, bounce=0.8} )

     newAsteroid.myName = “asteroid”

     – where to create the asteroid logic

     local whereFrom = math.random(3)

     if (whereFrom == 1) then

          – From the left and anywhere between y = 0->500

          newAsteroid.x = -60

          newAsteroid.y = math.random(500)

          newAsteroid:setLinearVelocity(math.random(40, 120), math.random(20, 60))

     elseif (whereFrom == 2) then

          newAsteroid.x = math.random(display.contentWidth)

          newAsteroid.y = -60

          newAsteroid:setLinearVelocity(math.random(-40, 40), math.random(40, 120))

     elseif (whereFrom == 3) then

          newAsteroid.x = display.contentWidth + 60

          newAsteroid.y = math.random(500)

          newAsteroid:setLinearVelocity(math.random(-120, -40), math.random(20, 60))

     end

     – Add torque to the asteroid image

     newAsteroid:applyTorque(math.random(-6,6))

end

– Function to shoot lasers

local function fireLaser()

     local newLaser = display.newImageRect( mainGroup, objectSheet, 5, 14, 40 )

     physics.addBody( newLaser, “dynamic”, { isSensor=true} )

     newLaser.isBullet = true

     newLaser.myName = “laser”

     newLaser.x = ship.x

     newLaser.y = ship.y

     newLaser:toBack()

     transition.to(newLaser, {y = -40, time=500,

          onComplete = function() display.remove(newLaser) end

     })

end

– Add event to shoot laser

ship:addEventListener(“tap”, fireLaser)

– Function to move the ship

local function dragShip(event)

     – ship var is the thing that was ‘touched’

     local ship = event.target

     – phase var for the 4 phases of the touch event “began”, “moved”, “ended”, “cancelled”

     local phase = event.phase

     if (“began” == phase) then

          – Set touch focus on the ship

          display.currentStage:setFocus(ship)

          – Store initial offset position

          ship.touchOffsetX = event.x - ship.x

     elseif (“moved” == phase) then

          – Move the ship to the new touch position

          – Using the offset value produces a smooth dragging effect

          --if (ship.x < display.contentWidth-50 and ship.x > 50) then

          ship.x = event.x - ship.touchOffsetX

          --end

     elseif (“ended” == phase or “cancelled” == phase) then

          – Release touch focus from ship

          display.currentStage:setFocus(nil)

     end

     return true – Prevents touch propagation to underlying objects

end

– Add event to drag ship

ship:addEventListener(“touch”, dragShip)

– Game loop function

local function gameLoop()

     – Create new asteroid

     createAsteroid()

     – Remove asteroids that have drifted off the screen

     for i = #asteroidsTable, 1, -1 do

          local thisAsteroid = asteroidsTable[i]

          if ( thisAsteroid.x < -100 or

               thisAsteroid.x > display.contentWidth + 100 or

               thisAsteroid.y < -100 or

               thisAsteroid.y > display.contentHeight + 100)

          then

               display.remove(thisAsteroid)

               table.remove(asteroidsTable, i)

          end

     end

end

gameLoopTimer = timer.performWithDelay( 500, gameLoop, 0 )

– Function to restore ship after death

local function restoreShip()

     – set body active to false so it does not interact with asteroids on fade-in

     ship.isBodyActive = false

     – Position and set the velocity of the ship

     ship:setLinearVelocity(0, 0)

     ship.x = display.contentCenterX

     ship.y = display.contentHeight-100

     – Fade in the ship

     – Alpha 0->1, 4000ms, onComplete turn body active, set died to false

     transition.to(ship, {alpha=1, time=4000,

          onComplete = function()

               ship.isBodayActive = true

               died = false

               print(“set died to false”)

          end

     })

end

local function onCollision( event )

     print(“onCollision called”)

     if (event.phase == “began”) then

          local obj1 = event.object1

          local obj2 = event.object2

          – Handle the laser / asteroid collision

          if ( (obj1.myName == “laser” and obj2.myName == “asteroid”) or

               (obj1.myName == “asteroid” and obj2.myName == “laser”) )

          then

               – Remove both the laser and asteroid

               display.remove(obj1)

               display.remove(obj2)

               for i = #asteroidsTable, 1, -1 do

                    if (asteroidsTable[i] == obj1 or asteroidsTable[i] == obj2) then

                         table.remove(asteroidsTable, i)

                         break

                    end

               end

               – Increase score

               score = score + 100

               scoreText.text = "Score: " … score

          – Handle the ship / asteroid collision

          elseif (  (obj1.myName == “ship” and obj2.myName == “asteroid”) or

                    (obj1.myName == “asteroid” and obj2.myName == “ship”) )

          then

               print(“inside death loop”)

               if (died == false) then

                    died = true

                    – Update lives

                    lives = lives - 1

                    livesText.text = "Lives: " … lives

                    if (lives == 0) then

                         display.remove(ship)

                    else

                         ship.alpha = 0

                         timer.performWithDelay( 1000, restoreShip )

                    end

               end

          end

     end

end

Runtime:addEventListener(“collision”, onCollision)

[/lua]

You misspell variable name. It should be

ship.isBodyActive = true -- line 218

It works now:)

Thanks so much for the help! I knew it would be something like this but I just couldn’t find anything

How does restoreShip function look like?

local function restoreShip() &nbsp; &nbsp; ship.isBodyActive = false &nbsp; &nbsp; ship:setLinearVelocity( 0, 0 ) &nbsp; &nbsp; ship.x = display.contentCenterX &nbsp; &nbsp; ship.y = display.contentHeight - 100 &nbsp; &nbsp; -- Fade in the ship &nbsp; &nbsp; transition.to( ship, { alpha=1, time=4000, &nbsp; &nbsp; &nbsp; &nbsp; onComplete = function() &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ship.isBodyActive = true &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; died = false &nbsp; &nbsp; &nbsp; &nbsp; end &nbsp; &nbsp; } ) end

I think my restoreShip() function is exactly the same?

[lua]

– Function to restore ship after death

local function restoreShip()

     – set body active to false so it does not interact with asteroids on fade-in

     ship.isBodyActive = false

     – Position and set the velocity of the ship

     ship:setLinearVelocity(0, 0)

     ship.x = display.contentCenterX

     ship.y = display.contentHeight-100

     – Fade in the ship

     – Alpha 0->1, 4000ms, onComplete turn body active, set died to false

     transition.to(ship, {alpha=1, time=4000,

          onComplete = function()

               ship.isBodayActive = true

               died = false

               print(“set died to false”)

          end

     })

end

[/lua]

Does collision between laser and asteroids also not work?

Thats the weird thing, the laser/asteroid collision is working perfectly as is the asteroid/asteroid collisions. Shooting an asteroid with the laser increments my score and both the objects disappear. 

I’m going to copy/paste my entire code below if that helps

[lua]


– main.lua

– Title:           Star Explorer - a space shooter game.

– Description:     Maneuver your starship through an asteroid field, destroying

–                  asteroids as you progress.

– Controls:        Tap on ship to fire. Drag to move left/right.

– Sounds:          Shooting/explosion sounds.

– Source:          https://docs.coronalabs.com/guide/programming/02/index.html


– Include physics (space so gravity = (0, 0))

local physics = require(“physics”)

physics.start()

physics.setGravity( 0, 0 )

– Seed the random number generator

math.randomseed(os.time())

– Load the image sheets

local sheetOptions =

{

     frames =

     {

          {    --1 Asteroid 1

               x = 0,

               y = 0,

               width = 102,

               height = 85

          },

          {    --2 Asteroid 2

               x = 0,

               y = 85,

               width = 90,

               height = 83

          },

          {    --3 Asteroid 3

               x = 0,

               y = 168,

               width = 100,

               height = 97

          },

          {    --4 Ship

               x = 0,

               y = 265,

               width = 98,

               height = 79

          },

          {    --5 Laser

               x = 98,

               y = 265,

               width = 14,

               height = 40

          },

     }

}

local objectSheet = graphics.newImageSheet( “gameObjects.png”, sheetOptions )

– Initialize variables

local lives = 3

local score = 0

local died = false

– Empty table initialized

local asteroidsTable = {}

local ship

local gameLoopTimer

local livesText

local scoreText

– Set up display groups

local backGroup = display.newGroup()    – Display group for background image

local mainGroup = display.newGroup()    – Display group for the main images (ships, asteroids)

local uiGroup = display.newGroup()      – Display group for the user interface

– Load the background

local background = display.newImageRect( backGroup, “background.png”, 800, 1400 )

background.x = display.contentCenterX

background.y = display.contentCenterY

– Load the ship

ship = display.newImageRect( mainGroup, objectSheet, 4, 98, 79 )

ship.x = display.contentCenterX

ship.y = display.contentHeight-100

physics.addBody(ship, {radius=30, isSensor=true})

ship.myName = “ship”

– Load the UI

livesText = display.newText(uiGroup, "Lives: " … lives, 200, 80, native.systemFont, 36)

scoreText = display.newText( uiGroup, "Score: " … score, 400, 80, native.systemFont, 36 )

– Hide the status bar

display.setStatusBar( display.HiddenStatusBar )

– Function to update text

local function updateText()

     livesText.text = "Lives: " … lives

     scoreText.text = "Score: " … score

end

– Function to create asteroids

local function createAsteroid()

     local newAsteroid = display.newImageRect(mainGroup, objectSheet, 1, 102, 85)

     – To keep track of the asteroids insert into a table

     table.insert(asteroidsTable, newAsteroid)

     physics.addBody( newAsteroid, “dynamic”, {radius=40, bounce=0.8} )

     newAsteroid.myName = “asteroid”

     – where to create the asteroid logic

     local whereFrom = math.random(3)

     if (whereFrom == 1) then

          – From the left and anywhere between y = 0->500

          newAsteroid.x = -60

          newAsteroid.y = math.random(500)

          newAsteroid:setLinearVelocity(math.random(40, 120), math.random(20, 60))

     elseif (whereFrom == 2) then

          newAsteroid.x = math.random(display.contentWidth)

          newAsteroid.y = -60

          newAsteroid:setLinearVelocity(math.random(-40, 40), math.random(40, 120))

     elseif (whereFrom == 3) then

          newAsteroid.x = display.contentWidth + 60

          newAsteroid.y = math.random(500)

          newAsteroid:setLinearVelocity(math.random(-120, -40), math.random(20, 60))

     end

     – Add torque to the asteroid image

     newAsteroid:applyTorque(math.random(-6,6))

end

– Function to shoot lasers

local function fireLaser()

     local newLaser = display.newImageRect( mainGroup, objectSheet, 5, 14, 40 )

     physics.addBody( newLaser, “dynamic”, { isSensor=true} )

     newLaser.isBullet = true

     newLaser.myName = “laser”

     newLaser.x = ship.x

     newLaser.y = ship.y

     newLaser:toBack()

     transition.to(newLaser, {y = -40, time=500,

          onComplete = function() display.remove(newLaser) end

     })

end

– Add event to shoot laser

ship:addEventListener(“tap”, fireLaser)

– Function to move the ship

local function dragShip(event)

     – ship var is the thing that was ‘touched’

     local ship = event.target

     – phase var for the 4 phases of the touch event “began”, “moved”, “ended”, “cancelled”

     local phase = event.phase

     if (“began” == phase) then

          – Set touch focus on the ship

          display.currentStage:setFocus(ship)

          – Store initial offset position

          ship.touchOffsetX = event.x - ship.x

     elseif (“moved” == phase) then

          – Move the ship to the new touch position

          – Using the offset value produces a smooth dragging effect

          --if (ship.x < display.contentWidth-50 and ship.x > 50) then

          ship.x = event.x - ship.touchOffsetX

          --end

     elseif (“ended” == phase or “cancelled” == phase) then

          – Release touch focus from ship

          display.currentStage:setFocus(nil)

     end

     return true – Prevents touch propagation to underlying objects

end

– Add event to drag ship

ship:addEventListener(“touch”, dragShip)

– Game loop function

local function gameLoop()

     – Create new asteroid

     createAsteroid()

     – Remove asteroids that have drifted off the screen

     for i = #asteroidsTable, 1, -1 do

          local thisAsteroid = asteroidsTable[i]

          if ( thisAsteroid.x < -100 or

               thisAsteroid.x > display.contentWidth + 100 or

               thisAsteroid.y < -100 or

               thisAsteroid.y > display.contentHeight + 100)

          then

               display.remove(thisAsteroid)

               table.remove(asteroidsTable, i)

          end

     end

end

gameLoopTimer = timer.performWithDelay( 500, gameLoop, 0 )

– Function to restore ship after death

local function restoreShip()

     – set body active to false so it does not interact with asteroids on fade-in

     ship.isBodyActive = false

     – Position and set the velocity of the ship

     ship:setLinearVelocity(0, 0)

     ship.x = display.contentCenterX

     ship.y = display.contentHeight-100

     – Fade in the ship

     – Alpha 0->1, 4000ms, onComplete turn body active, set died to false

     transition.to(ship, {alpha=1, time=4000,

          onComplete = function()

               ship.isBodayActive = true

               died = false

               print(“set died to false”)

          end

     })

end

local function onCollision( event )

     print(“onCollision called”)

     if (event.phase == “began”) then

          local obj1 = event.object1

          local obj2 = event.object2

          – Handle the laser / asteroid collision

          if ( (obj1.myName == “laser” and obj2.myName == “asteroid”) or

               (obj1.myName == “asteroid” and obj2.myName == “laser”) )

          then

               – Remove both the laser and asteroid

               display.remove(obj1)

               display.remove(obj2)

               for i = #asteroidsTable, 1, -1 do

                    if (asteroidsTable[i] == obj1 or asteroidsTable[i] == obj2) then

                         table.remove(asteroidsTable, i)

                         break

                    end

               end

               – Increase score

               score = score + 100

               scoreText.text = "Score: " … score

          – Handle the ship / asteroid collision

          elseif (  (obj1.myName == “ship” and obj2.myName == “asteroid”) or

                    (obj1.myName == “asteroid” and obj2.myName == “ship”) )

          then

               print(“inside death loop”)

               if (died == false) then

                    died = true

                    – Update lives

                    lives = lives - 1

                    livesText.text = "Lives: " … lives

                    if (lives == 0) then

                         display.remove(ship)

                    else

                         ship.alpha = 0

                         timer.performWithDelay( 1000, restoreShip )

                    end

               end

          end

     end

end

Runtime:addEventListener(“collision”, onCollision)

[/lua]

You misspell variable name. It should be

ship.isBodyActive = true -- line 218

It works now:)

Thanks so much for the help! I knew it would be something like this but I just couldn’t find anything