removeEventListener

I downloaded all the code for Highway Dodge by Daniel Williams on code.tutsplus.com, but every time the car crashes a second time this error message appears.


– “scene:create()” –
function scene:create( event )

-- Initialize the scene here. --
-- Example: add display objects to "sceneGroup", add touch listeners, etc. --
local sceneGroup = self.view

-- The following variables are known as forward declares. We'll create some for the player, enemy, lanes and establish default values. --
local lanes = {} -- create a table called lanes --
local playerCar -- a variable for the player car --
local laneID = 1 -- a variable for the lane id --
local enemyCars = {} -- a table to hold the enemy cars --
local enemyCounter = 1 -- start the enemy counter at 1 to keep track of the enemy cars --

local sendEnemyFrequency = 2500 -- defines how often to send enemy cars --
local tmrToSendCars -- a variable to hold a reference to the timer of sending cars --    

local playerScore = 0 -- start the player score at 0 --
local playerScoreText -- an object to hold the score text object --

– This function will increment the player score by 1. This function is called when the transition for the enemy car is complete and is off screen. –

local function incrementScore()

    playerScore = playerScore + 1 -- add playerScore by 1 --
    playerScoreText.text = "Score: "..playerScore -- update the on screen text --

end



-- moveCar will respond to the touch event on the lanes --
local function moveCar(event)

	if(event.phase == "ended") then
    
		laneID = event.target.id -- grab the lane id which will be 1, 2, or 3 --
		transition.to(playerCar, {x=lanes[laneID].x,time=50}) -- move the player car to the appropriate lane --

        return true -- to indicate a successful touch event, return true --
	end
end

– sendEnemyCar is where the magic happens. This function will send enemy cars from the top of the screen to the bottom of the screen. –
local function sendEnemyCar()

	enemyCars[enemyCounter] = display.newImageRect(sceneGroup, "images/enemyCar"..math.random(1,3)..".png", 50, 100) -- create a enemy car and grab a random enemy car image
	enemyCars[enemyCounter].x = lanes[math.random(1,#lanes)].x -- place the car on a random lane

		if(math.random(1,2) == 1) then enemyCars[enemyCounter].x = lanes[laneID].x; end -- 50% of the time, place the enemy car on the player car lane. 
	
    enemyCars[enemyCounter].y = -125 -- place the enemy off screen at the top --
	enemyCars[enemyCounter]:scale(1,-1) -- rotate the cars so they are facing down --
    physics.addBody(enemyCars[enemyCounter]) -- add a physics body to enemy cars --
	enemyCars[enemyCounter].bodyType = "kinematic" -- make the bodies kinematic --

	transition.to(enemyCars[enemyCounter], {y=display.contentHeight+enemyCars[enemyCounter].height+20, time=math.random(2250,3000), onComplete=function(self) display.remove(self); incrementScore(); end}) -- a transition that moves the enemy car towards the bottom of the screen. On completion, the enemy car object is removed from the game.

	enemyCounter = enemyCounter + 1 -- increase enemy counter by one for tracking --

	if(enemyCounter%2 == 0) then -- every other car, increase the speed of enemy frequency --
		sendEnemyFrequency = sendEnemyFrequency - 200 -- deduct the frequency by 200ms --
		
        if(sendEnemyFrequency < 800) then sendEnemyFrequency = 800; end -- cap the send enemy frequency to 800 --

		timer.cancel(tmrToSendCars) -- cancel the timer of sending cars
		tmrToSendCars = timer.performWithDelay(sendEnemyFrequency, sendEnemyCar, 0) -- recreate the time to send cars with update frequency
	end
end



-- Allow the player to return to the menu --
local function onPlayAgainTouch()
    composer.gotoScene("scene_menu", "fade") -- move player to menu --
end



-- This is the global collision scene. There are several ways to handle collisions and this is only one method. I felt this was the easiest for learning purposes. --

local function onGlobalCollision(event)
    if(event.phase == "began") then -- when the enemy car collides into the player car, this if/then statement will be true --        
        
        -- stop the game --
        transition.pause()
        timer.cancel(tmrToSendCars)
        physics.pause()

        -- remove event listeners from all lanes --
            for i=1,#lanes do
                lanes[i]:removeEventListener("touch", moveCar)
            end

I hope that wasn’t too much code.

Thanks in advance

No that wasn’t too much code, but if I understand correctly error happens in “for” loop which removes touch listeners from lanes. And you didn’t show us part where you add touch event listeners

So can you give us that part where you add your lines?

I found and reviewed the code on GitHub(https://github.com/tutsplus/Corona-HighwayDodge). It appears the error occurs because the instructor forgot to remove the collision event listener. You need to remove Runtime listeners manually. For more information - https://docs.coronalabs.com/guide/events/detectEvents/index.html#removing-event-listeners

You need to add this line:
Runtime:removeEventListener( "collision", onGlobalCollision ) -- remove the global event listener manually

before this section:

-- remove event listeners from all lanes
for i=1,#lanes do
    lanes[i]:removeEventListener("touch", moveCar)
end
1 Like

It works! Thanks bgmadclown. Maybe you would be able to help me with another problem. I’ve been trying to get a section of code for a little 3 level game I’ve been working on, to see if I could actually someday make a real game, but the answer eludes me.

Like many games you start on the menu page, then you tap options btn.
On the options page you tap the green png ball (not r, g, b) then tap the menu btn.
Again on the menu page you tap go to levels btn which takes you to level 1.
I want the green ball or which ever color ball is selected, to appear on level 1 and be used through out the rest of the game.

That’s my problem, I don’t know what the code would be for that and just to be completely honest I already asked this question, but the answers weren’t clear and they didn’t work.

Here’s my code:

– menu –

local composer = require( “composer” )
local scene = composer.newScene()

– include Corona’s “widget” library —
local widget = require (“widget”)


local playBtn1

local function onPlayBtn1Release() 	-- 'onRelease' event listener for playBtn --- 

			composer.gotoScene( "level1", "slideLeft", 500 ) -- go to Level1 scene --- 

		return true	 -- indicates successful touch --- 
end

local playBtn2

local function onPlayBtn2Release() 	-- 'onRelease' event listener for playBtn --- 

			composer.gotoScene( "options", "slideRight", 500 ) -- go to Options scene --- 

		return true	 -- indicates successful touch --- 
end

local playBtn3

local function onPlayBtn3Release() 	-- 'onRelease' event listener for playBtn --- 

			composer.gotoScene( "how to play", "fade", 500 ) -- go to How to Play scene --- 

		return true	 -- indicates successful touch --- 
end

function scene:create( event )
local sceneGroup = self.view

-- display a background image --- 
local background = display.newImageRect( "background.png", display.actualContentWidth, display.actualContentHeight )
background.anchorX = 0
background.anchorY = 0
background.x = 0 + display.screenOriginX 
background.y = 0 + display.screenOriginY 


-- create/position logo/title image on upper-half of the screen --- 
local titleLogo = display.newImageRect( "logo.png", 300, 40 ) 
titleLogo.x = display.contentCenterX
titleLogo.y = 40

playBtn1 = widget.newButton{
	label="Go to Levels",
	labelColor = { default={ 0, 0, 0 }, over={255/255, 0, 0} },
	defaultFile="buttonDefault1.png",
	overFile="buttonOver1.png",		
	width=200, 
	height=30,
	onRelease = onPlayBtn1Release	-- event listener function --- 
}
playBtn1.x = display.contentCenterX
playBtn1.y = display.contentHeight - 190

playBtn2 = widget.newButton{
	label="Options",
	labelColor = { default={ 0, 0, 0 }, over={128} },
	defaultFile="buttonDefault2.png",	
	overFile="buttonOver2.png",			
	width=200, 
	height=30,
	onRelease = onPlayBtn2Release	-- event listener function --- 
}
playBtn2.x = display.contentCenterX
playBtn2.y = display.contentCenterY + 20

playBtn3 = widget.newButton{
	label="How to Play",
	labelColor = { default={ 0, 0, 0 }, over={128} },
	defaultFile="buttonDefault3.png",	
	overFile="buttonOver3.png",			
	width=200, 
	height=30,
	onRelease = onPlayBtn3Release	-- event listener function --- 
}
playBtn3.x = display.contentCenterX
playBtn3.y = display.contentCenterY + 70

-- all display objects must be inserted into group --- 
sceneGroup:insert( background )
sceneGroup:insert( titleLogo )
sceneGroup:insert( playBtn1 )
sceneGroup:insert( playBtn2 )
sceneGroup:insert( playBtn3 )

end


function scene:show( event )
local sceneGroup = self.view
local phase = event.phase

if phase == "will" then

	-- Called when the scene is still off screen and is about to move on screen --- 
elseif phase == "did" then
	-- Called when the scene is now on screen --- 
	-- 
	-- INSERT code here to make the scene come alive - e.g. start timers, begin animation, play audio, etc. --- 
end	

end


function scene:hide( event )
local sceneGroup = self.view
local phase = event.phase

if event.phase == "will" then
	-- Called when the scene is on screen and is about to move off screen --- 
	--
	-- INSERT code here to pause the scene - e.g. stop timers, stop animation, unload sounds, etc.) --- 
elseif phase == "did" then
	-- Called when the scene is now off screen --- 
end	

end


function scene:destroy( event )
local sceneGroup = self.view

-- Called prior to the removal of scene's "view" (sceneGroup) --- 
-- 
-- INSERT code here to cleanup the scene - e.g. remove display objects, remove touch listeners, save state, etc. ---

if playBtn1 then
	playBtn1:removeSelf()	-- widgets must be manually removed ---
	playBtn1 = nil

elseif playBtn2 then
	playBtn2:removeSelf()	-- widgets must be manually removed ---
	playBtn2 = nil

elseif playBtn3 then
	playBtn3:removeSelf()	-- widgets must be manually removed ---
	playBtn3 = nil
end

end


– Listener setup —
scene:addEventListener( “create”, scene )
scene:addEventListener( “show”, scene )
scene:addEventListener( “hide”, scene )
scene:addEventListener( “destroy”, scene )


return scene

– options –

local composer = require( “composer” )
local scene = composer.newScene()

– include Corona’s “widget” library —
local widget = require (“widget”)


– forward declarations and other locals —
local screenW, screenH, halfW = display.actualContentWidth, display.actualContentHeight, display.contentCenterX

function scene:create( event )

-- Called when the scene's view does not exist. ---
-- 
-- INSERT code here to initialize the scene - e.g. add display objects to 'sceneGroup', add touch listeners, etc.

local sceneGroup = self.view

-- We need physics started to add bodies, but we don't want the simulaton running until the scene is on the screen. ---
physics.start()
physics.pause()

local function onMenuTouch(event)
		if(event.phase == "ended") then
			composer.gotoScene("menu", "slideLeft") 
		end
	return true 
end

– display a options background image —
local background = display.newImageRect( “background.png”, display.actualContentWidth, display.actualContentHeight )
background.anchorX = 0
background.anchorY = 0
background.x = 0 + display.screenOriginX
background.y = 0 + display.screenOriginY


–Function to handle button events —
local function handleButtonEvent( event )

if ( "ended" == event.phase ) then
    print( "Menu Button was pressed and released" )
end

end

local menuBtn = widget.newButton(
{
label=“Menu”,
labelColor = { default={128}, over={128} },
width = 55,
height = 20,
defaultFile = “homeBtnDefault.png”,
overFile = “homeBtnOver.png”,
onEvent = handleButtonEvent

}

)

– Center the button —
menuBtn.x = display.contentCenterX -250
menuBtn.y = display.contentCenterY -140
menuBtn:addEventListener(“touch”, onMenuTouch)


local textObjOptions = display.newText(“Options”, 100, 200, native.systemFont, 25)
textObjOptions:setFillColor(0, 0, 0)
textObjOptions.x = display.contentCenterX
textObjOptions.y = display.contentCenterY - 120


local textObjColor = display.newText(“Tap the ball”, 150, 20, native.systemFont, 20)
textObjColor:setFillColor(0, 0, 0)
textObjColor.x = display.contentCenterX - 160
textObjColor.y = display.contentCenterY - 40


local blueBall = display.newImageRect( “blueBall.png”, 25, 25 )
blueBall.x = display.contentCenterX - 150
blueBall.y = display.contentCenterY - 10
physics.addBody( blueBall, “static”, { density=1.0, radius=12 } )

	local pinkBall = display.newImageRect( "pinkBall.png", 25, 25 ) 
	pinkBall.x = display.contentCenterX - 190   
	pinkBall.y = display.contentCenterY - 10
	physics.addBody( pinkBall, "static", { density=1.0, radius=12 } )


			local greenBall = display.newImageRect( "greenBall.png", 25, 25 ) 
			greenBall.x = display.contentCenterX - 110   
			greenBall.y = display.contentCenterY - 10
			physics.addBody( greenBall, "static", { density=1.0, radius=12 } )

sceneGroup:insert( background )
sceneGroup:insert( menuBtn ) 
sceneGroup:insert( textObjOptions )
sceneGroup:insert( textObjColor )  
sceneGroup:insert( blueBall ) 
sceneGroup:insert( pinkBall ) 
sceneGroup:insert( greenBall )

end


function scene:show( event )
local sceneGroup = self.view
local phase = event.phase

if phase == "will" then
	-- Called when the scene is still off screen and is about to move on screen ---
elseif phase == "did" then
	-- Called when the scene is now on screen ---
	-- 
	-- INSERT code here to make the scene come alive - e.g. start timers, begin animation, play audio, etc. ---
	physics.start()
end

end


function scene:hide( event )
local sceneGroup = self.view

local phase = event.phase

if event.phase == "will" then
	-- Called when the scene is on screen and is about to move off screen ---
	--
	-- INSERT code here to pause the scene - e.g. stop timers, stop animation, unload sounds, etc.) ---
	physics.stop()
elseif phase == "did" then
	-- Called when the scene is now off screen ---
end	

end


function scene:destroy( event )

-- Called prior to the removal of scene's "view" (sceneGroup) ---
-- 
-- INSERT code here to cleanup the scene - e.g. remove display objects, remove touch listeners, save state, etc. ---
local sceneGroup = self.view

package.loaded[physics] = nil
physics = nil

end


– Listener setup —
scene:addEventListener( “create”, scene )
scene:addEventListener( “show”, scene )
scene:addEventListener( “hide”, scene )
scene:addEventListener( “destroy”, scene )


return scene

– level1 –

local composer = require( “composer” )
local scene = composer.newScene()

– include Corona’s “widget” library —
local widget = require (“widget”)

– include Corona’s “physics” library —
local physics = require (“physics”)
physics.start()


– forward declarations and other locals —
local screenW, screenH, halfW = display.actualContentWidth, display.actualContentHeight, display.contentCenterX

function scene:create( event )

local sceneGroup = self.view

-- We need physics started to add bodies, but we don't want the simulaton running until the scene is on the screen. ---
physics.start()
physics.pause()

local function onMenuTouch(event)
	
	if(event.phase == "ended") then
		composer.gotoScene("menu", "slideRight")
	end

end

-- display a background image --- 
local background = display.newImageRect( "background.png", display.actualContentWidth, display.actualContentHeight )
background.anchorX = 0
background.anchorY = 0
background.x = 0 + display.screenOriginX 
background.y = 0 + display.screenOriginY

–Function to handle button events —
local function handleButtonEvent( event )

if ( "ended" == event.phase ) then
    print( "Menu Button was pressed and released" )
end

end

local menuBtn = widget.newButton(
{
label=“Menu”,
labelColor = { default={128}, over={128} },
width = 55,
height = 20,
defaultFile = “homeBtnDefault.png”,
overFile = “homeBtnOver.png”,
onEvent = handleButtonEvent
}
)

– Center the button —
menuBtn.x = display.contentCenterX -250
menuBtn.y = display.contentCenterY -140
menuBtn:addEventListener(“touch”, onMenuTouch)


local textObjOptions = display.newText(“Level1”, 100, 200, native.systemFont, 25)
textObjOptions:setFillColor(0, 0, 0)
textObjOptions.x = display.contentCenterX
textObjOptions.y = display.contentCenterY - 120


local greenBall = display.newImageRect( “greenBall.png”, 25, 25 )
greenBall.x = display.contentCenterX - 150
greenBall.y = display.contentCenterY - 110
physics.addBody( greenBall, “dynamic”, { density=1.0, friction=0.5, bounce=0.1, radius=12 } )


local blackBar = display.newImageRect( “blackBar.png”, 70, 10 )
blackBar.x = 90
blackBar.y = 180
physics.addBody( blackBar, “static”, { density=1.0, friction=0.3, bounce=1 } )


local blackBar2 = display.newImageRect( “blackBar.png”, 70, 10 )
blackBar2.x = 300
blackBar2.y = 230
physics.addBody( blackBar2, “static”, { density=1.0, friction=0.3, bounce=1 } )


–>>all display objects must be inserted into group<<— REVIEW GROUPS >>>-------

sceneGroup:insert( background ) 
sceneGroup:insert( menuBtn ) 
sceneGroup:insert( textObjOptions )
sceneGroup:insert( greenBall )
sceneGroup:insert( blackBar )
sceneGroup:insert( blackBar2 )  

end

function scene:show( event )
local sceneGroup = self.view
local phase = event.phase

if phase == "will" then
	-- Called when the scene is still off screen and is about to move on screen ---
elseif phase == "did" then
	-- Called when the scene is now on screen ---
	-- 
	-- INSERT code here to make the scene come alive - e.g. start timers, begin animation, play audio, etc. ---
	physics.start()
end

end


function scene:hide( event )
local sceneGroup = self.view

local phase = event.phase

if event.phase == "will" then
	-- Called when the scene is on screen and is about to move off screen ---
	--
	-- INSERT code here to pause the scene - e.g. stop timers, stop animation, unload sounds, etc.) ---
	physics.stop()
elseif phase == "did" then
	-- Called when the scene is now off screen ---
end	

end


function scene:destroy( event )

-- Called prior to the removal of scene's "view" (sceneGroup) ---
-- 
-- INSERT code here to cleanup the scene - e.g. remove display objects, remove touch listeners, save state, etc. ---
local sceneGroup = self.view

package.loaded[physics] = nil
physics = nil

end


– Listener setup —
scene:addEventListener( “create”, scene )
scene:addEventListener( “show”, scene )
scene:addEventListener( “hide”, scene )
scene:addEventListener( “destroy”, scene )


return scene

Thanks in advance

I’m sorry, I can’t debug your code but here’s a sample project. Not the best application or the code for it but I’m sure you’ll understand how it works. You can work on it to make it better.demo.zip (1.8 KB)

Thanks I’ll give it a try.

Just a friendly piece of advice:

  1. Don’t just copy and paste over 12,400 characters worth of code, spread across several files, containing references to files which makes the code impossible to run without rewriting parts of it, etc., with a question like: “Can you fix this for me?”

  2. If for some reason you do post something like that, then at the very least format it correctly.

  3. Instead, you should ask specific questions and only post the required code for said question, i.e. limit the scope of your questions. Then, explain what you’ve done, what you expected to happen and what actually happens. This will make it easier for others to help you and it shows that you’ve also tried working out the problem for yourself, which makes others more willing to help you.

3 Likes