Hi Guys,
Getting stuck in a code I am playing around with. I am getting run time scene_game.lua:290: attempt to call method ‘removeEventListener’ (a nil value) error. 290 is referring to this part of the code
for i=1,#lanes do lanes[i]:removeEventListener("touch", moveCar) end
The funny part is this error does not get invoked when the collision in
elseif (self=="enemy" and other=="player") then
Rather, it only gets invoked when this part of the code shown below gets executed.
elseif (self=="player" and other=="enemy") then
The whole section of the code is provided below for Your reference. Pls help!
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 playerCar1 -- a variable for the player car local sprite local laneID = 1 -- a variable for the land 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 sheetInfo = require("zo") local myImageSheet = graphics.newImageSheet( "zo.png", sheetInfo:getSheet() ) local sequenceData = { { name="walk", -- name of the animation sheet=myImageSheet, -- the image sheet start=sheetInfo:getFrameIndex("1"), -- first frame count=4, -- number of frames time=700, -- speed loopCount=0 -- repeat } } local sheetInfo2 = require("opo") local myImageSheet2 = graphics.newImageSheet( "opo.png", sheetInfo2:getSheet() ) local sequenceData2 = { { name="walk2", -- name of the animation sheet=myImageSheet, -- the image sheet start=sheetInfo:getFrameIndex("1"), -- first frame count=4, -- number of frames time=700, -- speed loopCount=0 -- repeat } } chk=0 function messenger2(text) if chk==0 then g4A = display.newGroup() halt1= display.newRect( -30 , 150, 50+100\*9, 44\*2+30-65 ) halt1.alpha=.85 halt1.anchorX=0 halt1.anchorY=0 halt1:setFillColor( .2, .2, .2 ,.95) halt1:setStrokeColor( .8, .8 ,.8 ) halt1.strokeWidth = .51 audio.play(levelup) halt1text = display.newText( text, 235, 44\*3+185-140,native.systemFont, 26 ) halt1text:setFillColor( .8, .8, .8 ) g4A:insert( halt1 ) g4A:insert( halt1text ) transition.fadeOut( g4A, { time=2500, transition=easing.inCirc } ) sceneGroup:insert(g4A) end end local function incrementScore() playerScore = playerScore + 1 -- add playerScore by 1 playerScoreText.text = "Score: "..playerScore -- update the on screen text if playerScore\>bestscore then bestscore=playerScore messenger2("New high score reached") chk=1 loadsave.saveTable(bestscore, "Bestscorenow.json", system.DocumentsDirectory) end 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 transition.to(playerCar1, {x=lanes[laneID].x,time=50}) -- move the player car to the appropriate lane transition.to(sprite, {x=lanes[laneID].x,time=50}) -- move the player car to the appropriate lane audio.play(movingck) 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() if(enemyCounter%7 == 0) then enemyCars[enemyCounter] = display.newImageRect(sceneGroup, "tr.png", 20, 20) 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.8,-1.65) -- 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 enemyCars[enemyCounter].id = "trophy" -- id 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 \< 850) then sendEnemyFrequency = 850; 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 else enemyCars[enemyCounter] = display.newSprite(sceneGroup, myImageSheet2, sequenceData2 ) enemyCars[enemyCounter]:setSequence("walk2") enemyCars[enemyCounter]:play() 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.8,-1.65) -- rotate the cars so they are facing down local offsetRectParams = { halfWidth=20, halfHeight=20, x=0, y=60, angle=0 } physics.addBody(enemyCars[enemyCounter], { box=offsetRectParams } ) -- add a physics body to enemy cars enemyCars[enemyCounter].bodyType = "kinematic" -- make the bodies kinematic enemyCars[enemyCounter].id = "enemy" -- id 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 \< 850) then sendEnemyFrequency = 850; 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 end -- Allow the player to return to the menu local function onPlayAgainTouch() composer.gotoScene("scene\_menu", "fade") -- move player to menu end local function playersdead() audio.play(deads) print(deads) -- stop the game transition.pause() timer.cancel(tmrToSendCars) physics.pause() playerCar1.isVisible = true playerCar.alpha = 0 sprite.alpha = 0 -- remove event listeners from all lanes for i=1,#lanes do lanes[i]:removeEventListener("touch", moveCar) end Runtime:removeEventListener( "collision",onGlobalCollision ) local gameOverBackground = display.newRect(sceneGroup, 0, 0, display.actualContentWidth, display.actualContentHeight) -- display an opaque background graphic for some game over polish gameOverBackground.x = display.contentCenterX gameOverBackground.y = display.contentCenterY gameOverBackground:setFillColor(0) gameOverBackground.alpha = 0.5 -- Create a text object that will display game over text local gameOverText = display.newText( sceneGroup, "Game Over!", 100, 200, native.systemFontBold, 36 ) gameOverText.x = display.contentCenterX gameOverText.y = 150 gameOverText:setFillColor( 1, 1, 1 ) wpmaGlobalAdmob.showAdmobInterstitialAd() wpmaGlobalAdmob.loadAdmobInterstitialAd() -- create a button that allows the player to return to the local playAgain = widget.newButton { width = 220, height = 100, defaultFile = "images/btn-blank.png", overFile = "images/btn-blank.png", label = "Menu", font = system.defaultFontBold, fontSize = 32, labelColor = { default={ 0, 0, 0 }, over={ 0, 0, 0, 0.5 } }, onEvent = onPlayAgainTouch } playAgain.x = display.contentCenterX playAgain.y = gameOverText.y + 100 sceneGroup:insert(playAgain) end local function trophyz() audio.play(uplevel) 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 local self = event.object2.id local other = event.object1.id print\_r( self) --the first object in the collision print\_r( other ) --the second object in the collision -- print\_r( event.element1 ) --the element (number) of the first object which was hit in the collision -- print\_r( event.element2 ) if (self=="player" and other=="trophy") then event.object1:removeSelf() trophyz() elseif (self=="trophy" and other=="player") then event.object2:removeSelf() trophyz() elseif (self=="player" and other=="enemy") then playersdead() print("Someting screwy here") elseif (self=="enemy" and other=="player") then playersdead() --display.remove(self) else print("U SHOULD NOT BE HERE") end --END COLLISION end end local background = display.newImageRect(sceneGroup, "images/background.png", 475, 713) -- create the background image object background.x = display.contentCenterX -- place the graphic in the center of the x-axis background.y = display.contentCenterY -- place the graphic in the center of the y-axis for i=1,3 do -- loop 3 times to create 3 lanes for our game lanes[i] = display.newImageRect(sceneGroup, "images/lane.png", 79, 713) lanes[i].x = (display.contentCenterX - 79\*2) + (i\*80) lanes[i].y = display.contentCenterY lanes[i].id = i lanes[i]:addEventListener("touch", moveCar) -- add an event listener to the lanes that will respond to touch events. end playerScoreText = display.newText(sceneGroup, "Score: "..playerScore, 0, 0, native.systemFont, 36) -- Create a text object that will display the player score playerScoreText.x = display.contentCenterX playerScoreText.y = 25 playerCar = display.newImageRect(sceneGroup, "images/playerCar.png", 60, 60) -- create the player car image object playerCar.anchorY = 1 -- set the anchor point to 1 which is the bottom of the graphic playerCar.x = lanes[1].x -- put the player car on the first lane playerCar.y = display.contentHeight-70 -- place the car at the bottom of the screen physics.addBody(playerCar) -- add a physics body to the car playerCar.bodyType = "dynamic" -- make the car a dynamic body type playerCar.id = "player" playerCar1 = display.newImageRect(sceneGroup, "images/playerCar11.png", 50, 100) -- create the player car image object playerCar1.anchorY = 1 -- set the anchor point to 1 which is the bottom of the graphic playerCar1.x = lanes[1].x -- put the player car on the first lane playerCar1.y = display.contentHeight -- place the car at the bottom of the screen -- id -- physics.addBody(playerCar1) -- add a physics body to the car -- playerCar1.bodyType = "dynamic" -- make the car a dynamic body type sprite = display.newSprite( myImageSheet, sequenceData ) sprite:scale( 1.6, 1.6) sprite.anchorY = 1 sprite:setSequence("walk") sprite:play() sprite.x = lanes[1].x -- put the player car on the first lane sprite.y = display.contentHeight -- place the car at the bottom of the screen playerCar1.isVisible = false playerCar.isVisible = true playerCar.alpha = 0 tmrToSendCars = timer.performWithDelay(sendEnemyFrequency, sendEnemyCar, 0) -- start a timer to send cards. A 0 means run forever Runtime:addEventListener( "collision", onGlobalCollision ) -- create a global event listener to listen for any collision. end