Getting errors with my fall detection/replay menu

in the “enter frame” function, there is a statement which detects fall - when fall limit is reached, it pauses the game and brings up options. I use the same function i use for pausing the game but this time it doesn’t work - I’m not exactly sure why that is. 

The errors I get are are line 319 “attempt to remove event listener a nil value” and when I hit replay, the menu does not disappear and then I get “setFrame a nil value”

Here is the code for the entire main game file - sorry for the length, I didn’t want to leave anything out.

Thanks!!!

require ("config") require ("sprite") --physics.setDrawMode( "hybrid" ) local M = {} local player = false local level = false local gui = false local direction = 1 local paused = false local backgrounds = false local levelGroup = false local LoadLevel = false local maxJumps = 3 local Jump = maxJumps local maxFall = 2000 local canPlayHit = 0 local killZone = maxFall local moveSpeed = 30; local moveX = 0; local moveY = 0; local motionx = 0 local speed = 7 local menuPause = false --local rotation = 0; local words = require "words" local lastBlurb = false local blinkers = false local levels = { { "levels.LS\_Level\_1\_LY", "levels.LS\_Level\_2\_LY", "levels.LS\_Level\_3\_LY", "levels.LS\_Level\_4\_LY", "levels.LS\_Level\_5\_LY", "levels.LS\_Level\_6\_LY", }, { "levels.LS\_Level2\_1\_LY", "levels.LS\_Level2\_2\_LY", }, { "levels.LS\_Level3\_1\_JB", "levels.LS\_Level\_3\_2\_JB", "levels.LS\_Level\_3\_3\_JB", "levels.LS\_level\_3\_4\_JB", "levels.LS\_level\_3\_5\_JB", "levels.LS\_level\_3\_6\_JB", "levels.LS\_level\_3\_7\_JB", "levels.LS\_level\_3\_8\_JB", }, { "levels.LS\_level\_4\_3\_JB", "levels.LS\_level\_4\_4\_JB", "levels.LS\_level\_4\_5\_JB", }, { "levels.LS\_Level5\_1\_LY", }, { "levels.LS\_Level6\_1\_LY", "levels.LS\_Level6\_2\_LY", "levels.LS\_Level6\_3\_LY", "levels.LS\_Level6\_4\_LY", "levels.LS\_Level6\_5\_LY", "levels.LS\_Level6\_6\_LY", "levels.LS\_Level6\_7\_LY", "levels.LS\_Level6\_8\_LY", }, } local levelBackgrounds = { "LS\_Background\_LY\_1", "LS\_Background\_Summer", "LS\_Background\_LY\_3", "LS\_Background\_Winter", "LS\_Background\_LY\_5", "LS\_Background\_Dawn", } local backgroundGroups = { {false}, {"LS\_Background\_Summer\_Foreground",0}, {false}, {"LS\_Background\_Winter\_Foreground",0}, {false}, {"LS\_Background\_Dawn\_Foreground",0}, } local screenW, screenH, halfW = display.contentWidth, display.contentHeight, display.contentWidth\*0.5 collect = 0 local borderBottom = display.newRect( 0, 0, 0, 1 ) borderBottom:setReferencePoint(display.BottomCenterReferencePoint) local function phrase() return words[math.random(1,#words)] end local function pickupCollision( self, event ) if event.phase == "began" then transition.to(self,{time=200, delta=true, xScale=-0.99, y=-100, onComplete=display.remove}) playSound( sounds.collect ) collect = collect + 1 collection.text = tostring(collect) end end local function triangleCollision( self, event ) if event.phase == "began" then if currentLevel \>= #levels[currentWorld] then timer.performWithDelay(0,function() currentWorld = currentWorld + 1 if currentWorld \> 8 then director:changeScene("menu") else director:changeScene("levelSelect") end end) else physics.pause() pauseButton:removeSelf() pauseButton:removeEventListener("touch", pauseMenu) Runtime:removeEventListener("accelerometer", onTilt) --Runtime:removeEventListener("enterFrame", pauseGame) top:removeEventListener("touch", jumpSquare) right:removeEventListener("touch", onRightTouch) Runtime:removeEventListener("enterFrame", movePlayer) Runtime:removeEventListener("touch", stopPlayer) endMenu = display.newGroup() endScreen = display.newImage(endMenu,"assets/LS\_POPUP\_BG\_SD001.png",170,170) replaymenuButton = display.newImage(endMenu,"assets/LS\_BTN\_REPLAY\_SD001.png",550,500) menumenuButton = display.newImage(endMenu,"assets/LS\_BTN\_MENU.png",550,400) nextLevel = display.newImage(endMenu,"assets/LS\_BTN\_NEXT\_SD001.png",550,300) group:insert(endMenu) endMenu:toFront() --resumemenuButton:addEventListener("touch",resumeButton) replaymenuButton:addEventListener("touch",replayButtonEnd) menumenuButton:addEventListener("touch",menuButton) nextLevel:addEventListener("touch", function(event) if event.phase == "ended" then timer.performWithDelay(0,function() endMenu:removeSelf() physics.start() pauseButton = display.newImage("assets/LS\_ICON\_PAUSE.png",15,0) Runtime:addEventListener("enterFrame", movePlayer) right:addEventListener("touch", onRightTouch) left:addEventListener("touch", onLeftTouch) top:addEventListener( "touch", jumpSquare ) Runtime:addEventListener("accelerometer", onTilt) Runtime:addEventListener("touch", stopPlayer) pauseButton:addEventListener("touch", pauseMenu) player.x = 122 player.y = 74 player.rotation = 50 currentLevel = currentLevel + 1 LoadLevel() level.x = 0 level.y = 0 level:insert( levelGroup ) playSound( sounds.collect ) end) end end) -- Unload current level, load next level end end end local function speak(group,x,y) if lastBlurb then transition.to(lastBlurb,{time=300, xScale=0.1, yScale=0.2, onComplete=display.remove}) end local blurb = display.newGroup() local textBubble = image(blurb,"SpeechBubble",0,0,300,300) --function wrappedText(str, limit, size, font, color, indent, indent1) local text = wrappedText(phrase(), 20, 18, "acmesa", {0,0,0}) -- "A.C.M.E. Secret Agent" text.x = -230/2 text.y = -220/2 blurb:insert(text) group:insert(blurb) blurb.x, blurb.y = x, y transition.from(blurb, {time=300, xScale=0.1, yScale=0.2}) lastBlurb = blurb if math.random(1,100) \< 50 then textBubble.xScale = -1 blurb.x = blurb.x - 100 else blurb.x = blurb.x + 100 end end local function circleCollision( self, event ) if event.phase == "began" then speak(levelGroup,self.x,self.y-200) playSound( sounds.speech ) print "sound is being played" end end local function loadBackground(backgroundGroup) local imageName, offest = unpack( backgroundGroups[currentWorld] ) if imageName then --function image(group, name, x, y, w, h) local w,h = display.contentWidth, display.contentHeight image(backgroundGroup, imageName, w/2, h/2+offest+display.screenOriginY, w, h) end end LoadLevel = function() display.remove( levelGroup ) levelGroup = display.newGroup() local leveldata = require (levels[currentWorld][currentLevel]) for i=1,#leveldata do local obj = leveldata[i] if obj.name == "pickup" then --Probably should rename 'pickup' to Player Spawn player.x = obj.x player.y = obj.y elseif obj.name == "LS\_Collectable\_LY" then local pickup = object(levelGroup,"image",{obj.name,obj.x,obj.y,obj.width,obj.height},{255,255,255},{isSensor=true},"static") pickup.collision = pickupCollision pickup:addEventListener("collision", pickup) elseif obj.name == "LS\_LTriangle" then local triangle = object(levelGroup,"image",{obj.name,obj.x,obj.y,obj.width,obj.height},{255,255,255},{isSensor=true},"static") triangle.collision = triangleCollision triangle:addEventListener("collision", triangle) elseif obj.name == "CircleEnemy" then local circle = object(levelGroup,"sprite",{obj.name,obj.x,obj.y,obj.width,obj.height},{255,255,255},{isSensor=true, radius=100},"static") circle.collision = circleCollision circle:addEventListener("collision", circle) blinkers[#blinkers+1] = circle else object(levelGroup,"image",{obj.name,obj.x,obj.y,obj.width,obj.height},{255,255,255},{friction=0.8,radius=obj.width/2},"static") end end end function onRightTouch( event ) motionx = speed right:setFillColor(255,255,255,75) end function onLeftTouch(event) motionx = -speed left:setFillColor(255,255,255,75) end function movePlayer(event) player.x = player.x + motionx end function stopPlayer(event) if event.phase == "ended" then left:setFillColor(0,0,0,0) right:setFillColor(0,0,0,0) motionx = 0 end end function onTilt( event ) local u,v = player:getLinearVelocity() local tilt = event.yGravity local newDirection = 0 --system.setAccelerometerInterval( 30 ) This was moved to main.lua, smooths out accelerometer if math.abs(tilt) \> .1 then newDirection = tilt/math.abs(tilt) player:setLinearVelocity((-newDirection/2)\*200,v) else player:setLinearVelocity(0,v) newDirection = 0 end direction = newDirection end function jumpSquare( event ) if not paused then if( event.phase == "began" ) then if (Jump \> 1) then system.vibrate() player:applyForce( 0, -1850, player.x, player.y ) playSound( sounds.jump ) Jump = Jump - 1 end end end return true end local function pause() if paused then physics.start() else physics.pause() end paused = not paused end function pauseMenu( event ) if event.phase == "ended" then physics.pause() pauseButton:removeEventListener("touch", pauseMenu) Runtime:removeEventListener("accelerometer", onTilt) Runtime:removeEventListener("enterFrame", pauseGame) top:removeEventListener("touch", jumpSquare) right:removeEventListener("touch", onRightTouch) Runtime:removeEventListener("enterFrame", movePlayer) Runtime:removeEventListener("touch", stopPlayer) pauseButton:removeSelf() menu = display.newGroup() popupPause = display.newImage(menu,"assets/LS\_POPUP\_BG\_SD001.png",170,170) replaymenuButton = display.newImage(menu,"assets/LS\_BTN\_REPLAY\_SD001.png",550,500) menumenuButton = display.newImage(menu,"assets/LS\_BTN\_MENU.png",550,300) resumemenuButton = display.newImage(menu,"assets/LS\_ICON\_PLAY.png",15,0) resumemenuButton:addEventListener("touch",resumeButton) replaymenuButton:addEventListener("touch",replayButton) menumenuButton:addEventListener("touch",menuButton) group:insert(menu) --menu:toFront() print "pause game is being called" --menuPause = true end end function onEnterFrame(deltatime) level.x = -player.x + display.contentWidth / 2 level.y = -player.y + display.contentHeight / 2 local width = backgrounds[1].width local halfWidth = width/2 local height = backgrounds[1].height local halfHeight = height/2 backgrounds[1].x = (level.x / 1.5) % width - halfWidth backgrounds[2].x = (level.x / 1.5) % width + halfWidth backgrounds[3].x = (level.x / 1.5) % width + halfWidth backgrounds[4].x = (level.x / 1.5) % width - halfWidth backgrounds[1].y = (level.y / 1.5) % height + halfHeight backgrounds[2].y = (level.y / 1.5) % height - halfHeight backgrounds[3].y = (level.y / 1.5) % height + halfHeight backgrounds[4].y = (level.y / 1.5) % height - halfHeight if blinkers then for i=1,#blinkers do if math.random(1,100) == 4 then if blinkers[i] and blinkers[i].setFrame then blinkers[i]:setFrame(2) timer.performWithDelay(100,function() if blinkers and blinkers[i] then blinkers[i]:setFrame(1) end end) end end end end player.face.x, player.face.y = player.x, player.y killZone = maxFall if canPlayHit \> 0 then canPlayHit = canPlayHit - 1 end if (player.y \>= killZone) then --director:changeScene( "menu" ) pauseMenu{ phase = "ended"} end end function replayButtonEnd( event ) if event.phase == "began" then endMenu:removeSelf() physics.start() pauseButton = display.newImage(gui,"assets/LS\_ICON\_PAUSE.png",15,0) Runtime:addEventListener("enterFrame", movePlayer) right:addEventListener("touch", onRightTouch) left:addEventListener("touch", onLeftTouch) top:addEventListener( "touch", jumpSquare ) Runtime:addEventListener("accelerometer", onTilt) Runtime:addEventListener("touch", stopPlayer) pauseButton:addEventListener("touch", pauseMenu) timer.performWithDelay(0,function() player.x = 122 player.y = 74 player.rotation = 50 currentLevel = currentLevel LoadLevel() level.x = 0 level.y = 0 level:insert( levelGroup ) end) end end function replayButton( event ) if event.phase == "began" then menu:removeSelf() physics.start() pauseButton = display.newImage(gui,"assets/LS\_ICON\_PAUSE.png",15,0) Runtime:addEventListener("enterFrame", movePlayer) right:addEventListener("touch", onRightTouch) left:addEventListener("touch", onLeftTouch) top:addEventListener( "touch", jumpSquare ) Runtime:addEventListener("accelerometer", onTilt) Runtime:addEventListener("touch", stopPlayer) pauseButton:addEventListener("touch", pauseMenu) timer.performWithDelay(0,function() player.x = 122 player.y = 74 player.rotation = 50 currentLevel = currentLevel LoadLevel() level.x = 0 level.y = 0 level:insert( levelGroup ) end) end end function resumeButton( event ) if event.phase == "ended" then menu:removeSelf() physics.start() pauseButton = display.newImage(gui,"assets/LS\_ICON\_PAUSE.png",15,0) Runtime:addEventListener("enterFrame", movePlayer) right:addEventListener("touch", onRightTouch) left:addEventListener("touch", onLeftTouch) top:addEventListener( "touch", jumpSquare ) Runtime:addEventListener("accelerometer", onTilt) Runtime:addEventListener("touch", stopPlayer) pauseButton:addEventListener("touch", pauseMenu) end end function menuButton( event ) if event.phase == "ended" then setEnterFrame(false) blinkers = nil backgrounds = nil player = nil --Runtime:removeEventListener('accelerometer', moveSquare) Runtime:removeEventListener("accelerometer", onTilt) --Runtime:removeEventListener("enterFrame", moveSquare) -- Runtime:removeEventListener("accelerometer", onTilt) Runtime:removeEventListener("enterFrame", pauseGame) top:removeEventListener("touch", jumpSquare) right:removeEventListener("touch", onRightTouch) Runtime:removeEventListener("enterFrame", movePlayer) Runtime:removeEventListener("touch", stopPlayer) --pauseButton:removeEventListener("touch", pauseMenu) physics.pause() level.x = 0 level.y = 0 --level:insert( levelGroup ) playSound( sounds.collect ) director:changeScene("menu") --change scene to main menu end end -- Handler that gets notified when the alert closes local function onComplete( event ) if "clicked" == event.action then local i = event.index if 1 == i then -- Do nothing; dialog will simply dismiss elseif 2 == i then -- Open URL if "Learn More" (the 2nd button) was clicked --system.openURL( "http://www.hyperinkpress.com/images/kittenphotos/image83.jpg" ) end end end function M.new( event ) playInGame() group = display.newGroup() backgroundGroup = display.newGroup() paused = false physics.start() blinkers = {} --display.setDefault( 'background', 105,105,105 ) physics.setGravity(0,12) collFilter = nil gui = display.newGroup() level = display.newGroup() left = display.newRoundedRect(gui,0,480,640,360,100) left:setFillColor(0,0,0,0) right = display.newRoundedRect(gui,640,480,640,360,100) right:setFillColor(0,0,0,0) top = display.newRect(gui,0,80,1280,400) top:setFillColor(0,0,0,0) pauseButton = display.newImage(gui,"assets/LS\_ICON\_PAUSE.png",15,0) --pauseButton = image(gui,"LS\_ICON\_PAUSE",15,0) -- pauseButton:addEventListener("touch", function(event) -- if event.phase == "ended" then -- menuPause = true -- end -- end) collection = display.newText(gui,'0',1062,22,fontName,40) collection:setTextColor(0,0,0) image(gui, "coins",1000,50,103,26) backgrounds = { image(group,levelBackgrounds[currentWorld],1280/2,360, display.pixelHeight\*(960/640), display.pixelHeight), image(group,levelBackgrounds[currentWorld],1280/2,360, display.pixelHeight\*(960/640), display.pixelHeight), image(group,levelBackgrounds[currentWorld],1280/2,360, display.pixelHeight\*(960/640), display.pixelHeight), image(group,levelBackgrounds[currentWorld],1280/2,360, display.pixelHeight\*(960/640), display.pixelHeight), } group:insert(backgroundGroup) loadBackground(backgroundGroup) player = image(level,"LS\_LSquare\_LY", 122, 74, 85, 85) physics.addBody(player,"dynamic",{density = 1, friction = 0.8, bounce = 0.2}) player.name = "square" player.postCollision = function(self, event) Jump = maxJumps if event.force \> 10 and canPlayHit \<= 0 then playSound( sounds.hit ) canPlayHit = 50 player.face:setFrame(2) timer.performWithDelay(150,function() if player and player.face then player.face:setFrame(1) end end) end end player:addEventListener("postCollision", player) local spriteSheet = graphics.newImageSheet("assets/LS\_LSquare\_Face\_LY\_sprite.png", {width=85,height=85,numFrames=2} ) player.face = display.newSprite(spriteSheet, {name="blink",start=1,count=2}) level:insert(player.face) LoadLevel() level:insert( levelGroup ) player:toFront() player.face:toFront() --Runtime:addEventListener("enterFrame", pauseGame) Runtime:addEventListener("enterFrame", movePlayer) right:addEventListener("touch", onRightTouch) left:addEventListener("touch", onLeftTouch) --Runtime:addEventListener("enterFrame", moveSquare) top:addEventListener( "touch", jumpSquare ) Runtime:addEventListener("accelerometer", onTilt) Runtime:addEventListener("touch", stopPlayer) pauseButton:addEventListener("touch", pauseMenu) setEnterFrame(onEnterFrame) group:insert(level) group:insert(gui) --menu:toFront() -- local alert = native.showAlert( "Instructions", "Tap the bottom left or right of the screen to move. Tap the top half of the screen to jump. You may also tilt to move.", -- { "OK", "Want more?" }, onComplete ) local function clean() blinkers = nil backgrounds = nil player = nil --Runtime:removeEventListener('accelerometer', moveSquare) Runtime:removeEventListener("accelerometer", onTilt) --Runtime:removeEventListener("enterFrame", moveSquare) -- Runtime:removeEventListener("accelerometer", onTilt) Runtime:removeEventListener("enterFrame", pauseGame) top:removeEventListener("touch", jumpSquare) right:removeEventListener("touch", onRightTouch) Runtime:removeEventListener("enterFrame", movePlayer) Runtime:removeEventListener("touch", stopPlayer) --pauseButton:removeEventListener("touch", pauseMenu) setEnterFrame(false) physics.pause() end setOnBack( function() director:changeScene("menu") end ) return group, clean end return M&nbsp;

Hi there,

If you look at 319, you’ll see that you’re passing the function pauseMenu to removeEventListener.  However, this is occurring within the function in which pauseMenu is being defined, so at the time the Lua code is compiled, that reference is still nil, hence the error.

At line 314 (currently blank), try inserting this and seeing if it helps: [lua]pauseMenu = function() end[/lua].  This is just to pre-declare pauseMenu as something other than nil.

  • Andrew

Hi Andrew thanks for the reply, 

That did not specifically work, but maybe if I move some of the functions around, would that help do you think? 

Possibly, but unlikely for that specific error.  The other possibility is that there was no listener added for that function, so the error you’re getting is that it’s failing to remove something that wasn’t added in the first place.  That sounds plausible to me, since you said this code is being triggered when something falls off screen, but line 319 is about a pause button (which probably isn’t being displayed at that time).

Thanks again for the suggestions - I’ve been going through all my buttons/listeners and haven’t found anything out of whack. I’ll keep playing around with it though thank you! 

Hi there,

If you look at 319, you’ll see that you’re passing the function pauseMenu to removeEventListener.  However, this is occurring within the function in which pauseMenu is being defined, so at the time the Lua code is compiled, that reference is still nil, hence the error.

At line 314 (currently blank), try inserting this and seeing if it helps: [lua]pauseMenu = function() end[/lua].  This is just to pre-declare pauseMenu as something other than nil.

  • Andrew

Hi Andrew thanks for the reply, 

That did not specifically work, but maybe if I move some of the functions around, would that help do you think? 

Possibly, but unlikely for that specific error.  The other possibility is that there was no listener added for that function, so the error you’re getting is that it’s failing to remove something that wasn’t added in the first place.  That sounds plausible to me, since you said this code is being triggered when something falls off screen, but line 319 is about a pause button (which probably isn’t being displayed at that time).

Thanks again for the suggestions - I’ve been going through all my buttons/listeners and haven’t found anything out of whack. I’ll keep playing around with it though thank you!