Overlay Problem (attempt to index local 'parent' (a nil value))

I have a pause menu overlay with a button to restart the level. Since I have the function to restart a level in the scene where the game is played, I am trying to just use event.parent to call the function. However, it doesn’t work. Through various tests, I have determined that in the overlay event.parent is nil. I have tried the following:

--in the button listener local parent = event.parent parent.reset() --or local parent = event.parent parent:reset() --or event.parent.reset() --or event.parent:reset()

I tried the code in the docs, too. I couldn’t find any help in previous posts. Any ideas? 

Thanks in advance!

This might help. 

-------------------- -- pauseMenuOvly.lua -------------------- -- show the ovly with a 'restart level' btn -- when button is pressed, just close the overlay Composer.hideOverlay("fade", 400) -- when the scene hides it will call the function -- in the parent - game scene or level scene or whatever you call it function scene:hide( e ) local parent = e.parent if ( e.phase == "will" ) then elseif ( e.phase == "did" ) then parent:restartLevel() end end -------------------------------------------- --game or level scene -------------------------------------------- function scene:restartLevel() -- the overlay has now closed -- call you reset stuff here end

Good luck.  Hope this helps.

Bob

Unfortunately, I also have a resume button, which uses the scene:hide function as well. I did try the code just to see if it would work, and I started receiving a different error. When I would call the overlay (not when I tried to close it), it would run the scene:hide function (I don’t know why), and load the parent event properly, but when I tried to call the reset() function, it would say it was a nil method. I’m really at a loss for what could be the problem.

Thanks for your reply by the way.

without seeing most or all of your code, it is hard for me to answer the new error you mention.

So here is a complete little app that shows a plain screen for a game-scene. It has a pause button.  Press the pause button and the pause-overlay appears and has 2 buttons(Resume and Restart).

Click either one, and the ‘scene:hide’ sends to the game-scene either ‘RESUME’ or "RESTART’.

Create a new app for testing and use these 3 segments below to make a main.lua, gameScene.lua, and pauseOvly.lua. Just cut and paste in the code below into the 3 files. Jus the sure to have button images that are named the same as in my sample code.

Run the app and you should see how it works, and from that should be able to see how to apply that to your code.

If not, you may have to post a fair amount of your code for anyone to see what might be wrong. But, i think if you run this sample app you will likely see how to make everything work.

– main.lua

local composer = require( "composer" ) local scene = composer.newScene() display.setStatusBar( display.HiddenStatusBar ) composer.gotoScene("gameScene", {time=550, effect="crossFade"})

– gameScene.lua

composer = require('composer') local widget = require('widget') scene = composer.newScene() centerX = display.contentCenterX centerY = display.contentCenterY W = display.contentWidth H = display.contentHeight local gameSceneTitle local pauseBtn local statusText local function resumeGame() statusText.text = "GAME IS RESUMING" end local function restartLevel() print("restart the level") statusText.text = "RESTARTING THE LEVEL" end local function onPause(e) if e.phase == "ended" then local pauseOptions = { effect = "fade", time = 400, isModal = true } composer.removeHidden() composer.showOverlay( "pauseOvly", pauseOptions ) end end function scene:create(e) local sceneGroup = self.view local background = display.newRect(centerX,centerY, W,H) background:setFillColor(.1, .7, .1) background.x = centerX background.y = centerY pauseBtn = widget.newButton( { width = 200, height = 25 , id = 1, defaultFile = 'Images/pause.png', overFile = 'Images/pause\_dn.png', onEvent = onPause } ) pauseBtn.x = centerX pauseBtn.y = centerY - 100 statusText = display.newText("\*\*\*\*\*" ,centerX, H \* .2, nil, 18) statusText:setFillColor(0,0,0) sceneGroup:insert(background) sceneGroup:insert(pauseBtn) sceneGroup:insert(statusText) gameSceneTitle = display.newText('The Great Game', centerX, H \* .125) sceneGroup:insert(gameSceneTitle) end function scene:show(e) local phase = e.phase if "did" == phase then end end function scene:endPause(flag) print(" flag is " , flag) if flag == "RESUME" then resumeGame() elseif flag == "RESTART" then restartLevel() end end scene:addEventListener('create',scene) scene:addEventListener('show',scene) scene:addEventListener( "hide", scene ) scene:addEventListener( "destroy", scene ) return scene  

– pauseOvly.lua

composer = require('composer') local widget = require('widget') scene = composer.newScene() local centerX = display.contentCenterX local centerY = display.contentCenterY local W = display.contentWidth local H = display.contentHeight local restartLevelBtn local resumeBtn local flag = "RESUME" local pauseText local function onRestart(e) if e.phase == 'ended' then flag = "RESTART" composer.hideOverlay("fade", 400) end end local function onResume(e) if e.phase == 'ended' then flag = "RESUME" composer.hideOverlay("fade", 400) end end function scene:create(e) local sceneGroup = self.view local background = display.newRect(centerX,centerY, W,H) background.x = centerX background.y = centerY sceneGroup:insert(background) restartLevelBtn = widget.newButton( { width = 200, height = 25 , id = 1, defaultFile = 'Images/restart.png', overFile = 'Images/restart\_dn.png', onEvent = onRestart } ) restartLevelBtn.x = centerX restartLevelBtn.y = centerY - 100 sceneGroup:insert(restartLevelBtn) resumeBtn = widget.newButton( { width =200, height = 25, id = 2, defaultFile = 'Images/resume.png', overFile = 'Images/resume\_dn.png', onEvent = onResume } ) resumeBtn.x = centerX resumeBtn.y = centerY pauseText = display.newText("game is paused" ,centerX, H \* .2, nil, 18) pauseText:setFillColor(0,0,0) sceneGroup:insert(pauseText) sceneGroup:insert(resumeBtn) end function scene:show(e) local phase = e.phase if "did" == phase then end end function scene:hide( e ) local parent = e.parent if ( e.phase == "will" ) then elseif ( e.phase == "did" ) then parent:endPause(flag) end end scene:addEventListener('create',scene) scene:addEventListener('show',scene) scene:addEventListener( "hide", scene ) scene:addEventListener( "destroy", scene ) return scene 

Good luck

Bob

I ran the test code and it worked, but when I tried to apply it to my own code (as far as I can tell I’ve done everything right), I’m still getting the same problem. I get the error attempt to call field ‘endPause’ (a nil value). I did define an endPause function in my code, so I’m pretty sure this is the same problem as last time where it recognizes event.parent but not the method. Do you think it might be a bug in this build? I’m using 2017.3135.

Here are some code snippets that might be helpful:

In loadGame.lua:

local function onPauseBtnRelease(event) local options = { isModal = true, effect = "fade", time = 400, params = { } } physics.pause() composer.showOverlay("scenes.PauseMenu", options) end --later local function endPause(flag) print(" flag is " , flag) if flag == "RESUME" then return elseif flag == "RESTART" then reset() end end

In PauseMeny.lua:

local function onResumeBtnRelease( event) physics.start() flag = "RESUME" composer.hideOverlay( "fade", 400 ) return true -- indicates successful touch end local function onMenuBtnRelease( event ) composer.gotoScene("scenes.menu", "fade", 300) composer.removeScene("scenes.loadGame") return true end local function onRestartBtnRelease (event) flag = "RESTART" composer.hideOverlay( "fade", 400 ) return true end --scene:create makes the buttons here function scene:hide(event) local parent = event.parent if ( event.phase == "will" ) then elseif ( event.phase == "did" ) then parent:endPause(flag) end end

Any thoughts?

Thanks!

No, I do not think it is a bug in the sdk. You are using the last ‘stable’ release(2017.3135);  and most of the time these type of errors and issues are typos or scope issues.

In your code sample, loadGame.lua module, I think you have the function defined incorrectly.

It is should NOT be :

‘local function endPause(flag)’

It SHOULD be:

function scene:endPause(flag)

I think that should fix it.

Good luck!

Bob

That fixed it. Thanks so much for your help, time, and patience!

This might help. 

-------------------- -- pauseMenuOvly.lua -------------------- -- show the ovly with a 'restart level' btn -- when button is pressed, just close the overlay Composer.hideOverlay("fade", 400) -- when the scene hides it will call the function -- in the parent - game scene or level scene or whatever you call it function scene:hide( e ) local parent = e.parent if ( e.phase == "will" ) then elseif ( e.phase == "did" ) then parent:restartLevel() end end -------------------------------------------- --game or level scene -------------------------------------------- function scene:restartLevel() -- the overlay has now closed -- call you reset stuff here end

Good luck.  Hope this helps.

Bob

Unfortunately, I also have a resume button, which uses the scene:hide function as well. I did try the code just to see if it would work, and I started receiving a different error. When I would call the overlay (not when I tried to close it), it would run the scene:hide function (I don’t know why), and load the parent event properly, but when I tried to call the reset() function, it would say it was a nil method. I’m really at a loss for what could be the problem.

Thanks for your reply by the way.

without seeing most or all of your code, it is hard for me to answer the new error you mention.

So here is a complete little app that shows a plain screen for a game-scene. It has a pause button.  Press the pause button and the pause-overlay appears and has 2 buttons(Resume and Restart).

Click either one, and the ‘scene:hide’ sends to the game-scene either ‘RESUME’ or "RESTART’.

Create a new app for testing and use these 3 segments below to make a main.lua, gameScene.lua, and pauseOvly.lua. Just cut and paste in the code below into the 3 files. Jus the sure to have button images that are named the same as in my sample code.

Run the app and you should see how it works, and from that should be able to see how to apply that to your code.

If not, you may have to post a fair amount of your code for anyone to see what might be wrong. But, i think if you run this sample app you will likely see how to make everything work.

– main.lua

local composer = require( "composer" ) local scene = composer.newScene() display.setStatusBar( display.HiddenStatusBar ) composer.gotoScene("gameScene", {time=550, effect="crossFade"})

– gameScene.lua

composer = require('composer') local widget = require('widget') scene = composer.newScene() centerX = display.contentCenterX centerY = display.contentCenterY W = display.contentWidth H = display.contentHeight local gameSceneTitle local pauseBtn local statusText local function resumeGame() statusText.text = "GAME IS RESUMING" end local function restartLevel() print("restart the level") statusText.text = "RESTARTING THE LEVEL" end local function onPause(e) if e.phase == "ended" then local pauseOptions = { effect = "fade", time = 400, isModal = true } composer.removeHidden() composer.showOverlay( "pauseOvly", pauseOptions ) end end function scene:create(e) local sceneGroup = self.view local background = display.newRect(centerX,centerY, W,H) background:setFillColor(.1, .7, .1) background.x = centerX background.y = centerY pauseBtn = widget.newButton( { width = 200, height = 25 , id = 1, defaultFile = 'Images/pause.png', overFile = 'Images/pause\_dn.png', onEvent = onPause } ) pauseBtn.x = centerX pauseBtn.y = centerY - 100 statusText = display.newText("\*\*\*\*\*" ,centerX, H \* .2, nil, 18) statusText:setFillColor(0,0,0) sceneGroup:insert(background) sceneGroup:insert(pauseBtn) sceneGroup:insert(statusText) gameSceneTitle = display.newText('The Great Game', centerX, H \* .125) sceneGroup:insert(gameSceneTitle) end function scene:show(e) local phase = e.phase if "did" == phase then end end function scene:endPause(flag) print(" flag is " , flag) if flag == "RESUME" then resumeGame() elseif flag == "RESTART" then restartLevel() end end scene:addEventListener('create',scene) scene:addEventListener('show',scene) scene:addEventListener( "hide", scene ) scene:addEventListener( "destroy", scene ) return scene  

– pauseOvly.lua

composer = require('composer') local widget = require('widget') scene = composer.newScene() local centerX = display.contentCenterX local centerY = display.contentCenterY local W = display.contentWidth local H = display.contentHeight local restartLevelBtn local resumeBtn local flag = "RESUME" local pauseText local function onRestart(e) if e.phase == 'ended' then flag = "RESTART" composer.hideOverlay("fade", 400) end end local function onResume(e) if e.phase == 'ended' then flag = "RESUME" composer.hideOverlay("fade", 400) end end function scene:create(e) local sceneGroup = self.view local background = display.newRect(centerX,centerY, W,H) background.x = centerX background.y = centerY sceneGroup:insert(background) restartLevelBtn = widget.newButton( { width = 200, height = 25 , id = 1, defaultFile = 'Images/restart.png', overFile = 'Images/restart\_dn.png', onEvent = onRestart } ) restartLevelBtn.x = centerX restartLevelBtn.y = centerY - 100 sceneGroup:insert(restartLevelBtn) resumeBtn = widget.newButton( { width =200, height = 25, id = 2, defaultFile = 'Images/resume.png', overFile = 'Images/resume\_dn.png', onEvent = onResume } ) resumeBtn.x = centerX resumeBtn.y = centerY pauseText = display.newText("game is paused" ,centerX, H \* .2, nil, 18) pauseText:setFillColor(0,0,0) sceneGroup:insert(pauseText) sceneGroup:insert(resumeBtn) end function scene:show(e) local phase = e.phase if "did" == phase then end end function scene:hide( e ) local parent = e.parent if ( e.phase == "will" ) then elseif ( e.phase == "did" ) then parent:endPause(flag) end end scene:addEventListener('create',scene) scene:addEventListener('show',scene) scene:addEventListener( "hide", scene ) scene:addEventListener( "destroy", scene ) return scene 

Good luck

Bob

I ran the test code and it worked, but when I tried to apply it to my own code (as far as I can tell I’ve done everything right), I’m still getting the same problem. I get the error attempt to call field ‘endPause’ (a nil value). I did define an endPause function in my code, so I’m pretty sure this is the same problem as last time where it recognizes event.parent but not the method. Do you think it might be a bug in this build? I’m using 2017.3135.

Here are some code snippets that might be helpful:

In loadGame.lua:

local function onPauseBtnRelease(event) local options = { isModal = true, effect = "fade", time = 400, params = { } } physics.pause() composer.showOverlay("scenes.PauseMenu", options) end --later local function endPause(flag) print(" flag is " , flag) if flag == "RESUME" then return elseif flag == "RESTART" then reset() end end

In PauseMeny.lua:

local function onResumeBtnRelease( event) physics.start() flag = "RESUME" composer.hideOverlay( "fade", 400 ) return true -- indicates successful touch end local function onMenuBtnRelease( event ) composer.gotoScene("scenes.menu", "fade", 300) composer.removeScene("scenes.loadGame") return true end local function onRestartBtnRelease (event) flag = "RESTART" composer.hideOverlay( "fade", 400 ) return true end --scene:create makes the buttons here function scene:hide(event) local parent = event.parent if ( event.phase == "will" ) then elseif ( event.phase == "did" ) then parent:endPause(flag) end end

Any thoughts?

Thanks!

No, I do not think it is a bug in the sdk. You are using the last ‘stable’ release(2017.3135);  and most of the time these type of errors and issues are typos or scope issues.

In your code sample, loadGame.lua module, I think you have the function defined incorrectly.

It is should NOT be :

‘local function endPause(flag)’

It SHOULD be:

function scene:endPause(flag)

I think that should fix it.

Good luck!

Bob

That fixed it. Thanks so much for your help, time, and patience!