composer: gotoScene and returning from the called scene

I have multiple menus for my game that I need to be able to call and return from with the parent menu being usable. At this point I can call a new scene (menu) from the main scene (main menu), the called scene works fine. However when I return to the prior menu, the main or even a lower menu that is the parent of the last called scene the buttons no longer respond to events. I can click on them in the simulator and there is no response.

I have read the composer API documentation and looked on the forum. I have tried several different ways to try and get this resolved but not success so far. I am attaching the composer code for bit the main and one of the called scenes. If someone can please point out the mistakes I would appreciate it.

FIRST SCENE:

[lua]


– menu.lua


local composer = require(‘composer’) – Scene management
local scene = composer.newScene()
local controller = require(‘libs.controller’) – Gamepad support
local relayout = require(‘libs.relayout’) – Repositions elements on screen on window resize
– include Corona’s “widget” library
local widget = require (‘widget’) – Buttons


– MAIN MENU


function scene:create()
    local _W, _H, _CX, _CY = relayout._W, relayout._H, relayout._CX, relayout._CY
    --local calledScene = nil
    local group = self.view
 
  – MENU IMAGE, ‘buttons’ ARE TRANSPERANT OVER EXISTING ACTION LABELS IN JPG
 
    local backGroundImage1 = ‘images/backgrounds/mainMenuScreen.jpg’
    local backGround = display.newImageRect(backGroundImage1,1920, 1200)
          backGround.x = display.contentCenterX
          backGround.y = display.contentCenterY
    relayout.add(backGround)

    
  function onCharacterTouch(event)
    if “began” == event.phase then
      composer.gotoScene( ‘scenes.character’, “fade”, 1500)
      return true
    end
  end    
    --SET BUTTON THAT WILL CALL NEXT MENU SCENE
    characterButton = widget.newButton({
      width = 300,
      height = 50,
      x = display.contentCenterX,
      y = 600,
      onEvent = onCharacterTouch
      })
    
    group:insert(characterButton)
    relayout.add(characterButton)
 
end

function scene:show(event)
  local group = self.view
    print(“in show”, parent)
    if “did” == event.phase then
      – IS THIS MISPLACED?
      composer.removeScene(“menu”)
    end
    
end

function scene:hide( event )
    local sceneGroup = self.view
    local phase = event.phase
    if ( phase == “did” ) then
      ???
    end
end   

– Called when scene is about to move offscreen:
function scene:exit( event )
    local group = self.view
    
    – INSERT code here (e.g. stop timers, remove listenets, unload sounds, etc.)
end

– If scene’s view is removed, scene:destroyScene() will be called just prior to:
function scene:destroy( event )
    local group = self.view
    local shouldRecycle = true
    
– SHOULD THIS BE HERE AND IS IT REALLY PROVIDING ANYTHING?
–    if event.phase == “did” then
–        composer.removeScene(“menu”,shouldRecycle)
–    end

end


– END OF YOUR IMPLEMENTATION

– “create” event is dispatched if scene’s view does not exist
scene:addEventListener( “create” )

– “enter” event is dispatched whenever scene transition has finished
– is this needed once I return from the called scene ‘character_forum’??
scene:addEventListener( “enter” )

scene:addEventListener( “show” )

scene:addEventListener( “hide” )

– “exit” event is dispatched whenever before next scene’s transition begins
scene:addEventListener( “exit” )

– “destroy” event is dispatched before view is unloaded, which can be
– automatically unloaded in low memory situations, or explicitly via a call to
– storyboard.purgeScene() or storyboard.removeScene().
scene:addEventListener( “destroy” )


return scene
[/lua]

SECOND SCENE:

[lua]

– CALLED SCENE

local composer = require(‘composer’) – Scene management
local scene = composer.newScene()
local widget = require (‘widget’) – Buttons
local relayout = require(‘libs.relayout’) – Repositions elements on screen on window resize

function scene:create()
    local _W, _H, _CX, _CY = relayout._W, relayout._H, relayout._CX, relayout._CY
    local group = self.view
    
    – CALLED MENU SCENE FROM MAIN_FORUM SCENE
    
    local characterImage = ‘images/backgrounds/characterProfileScreen.jpg’
    local characterBackground = display.newImageRect(characterImage,1920, 1060)
    characterBackground.x = display.contentCenterX
    characterBackground.y = display.contentCenterY
    relayout.add(characterBackground)


  – EVENT HANDLER FOR BACK BUTTON, THIS DOES GO BACK TO MAIN MENU
  – ISSUE ONCE BACK AT MAIN MENU, MAIN MENU DOES NOT RESPOND TO TOUCH EVENTS
-----------------------------------------------------------------------------------  
  local function onBackTouch( event )
    if “began” == event.phase then
      composer.gotoScene(“menu”, “fade”, 1500 )
      return true
    end
  end

    – create a widget button to return to main menu
    backButton = widget.newButton({
        width = 300,
        height = 100,
        x = 1900 ,
        y = 55,
        onEvent = onBackTouch
    })
    group:insert(backButton)
    relayout.add(backButton)

end

function scene:show(event)
  local group = self.view
  local parent = event.parent  --reference to the parent scene object, GET A NIL VALUE HERE
   
    if “did” == event.phase then
      composer.removeScene(“menu”)
    end
    
end

function scene:hide( event )
    local sceneGroup = self.view
    local phase = event.phase
    local parent = event.parent  --reference to the parent scene object, AGAIN A NIL VALUE
    if ( phase == “did” ) then
      ???
-----------------------------------------------------------------------------------      
        – Call the THE PARENT SCENE, IS THIS NECESSARY TO GET MAIN MENU TO
        – RESPOND TO TOUCH EVENTS ONCE WE HAVE RETURNED???
       --parent:create()
-----------------------------------------------------------------------------------       
    end
end   

– Called when scene is about to move offscreen:
function scene:exit( event )
    local group = self.view
    – INSERT code here (e.g. stop timers, remove listenets, unload sounds, etc.)
    if event.phase == ‘will’ then
      
    end
end

– If scene’s view is removed, scene:destroyScene() will be called just prior to:
function scene:destroy( event )
    local group = self.view

    if backButton then
        backButton:removeSelf()    – widgets must be manually removed
    end
end

– “create” event is dispatched if scene’s view does not exist
scene:addEventListener( “create” )

scene:addEventListener( “show”, scene)

scene:addEventListener( “hide”, scene )

– “exit” event is dispatched whenever before next scene’s transition begins
scene:addEventListener( “exit” )

– “destroy” event is dispatched before view is unloaded, which can be
– automatically unloaded in low memory situations, or explicitly via a call to

scene:addEventListener( “destroy” )


return scene
[/lua]

In your first code file, within the :create() function, you have function onCharacterTouch(event) which is global. It shouldn’t be.

I’m not saying that’s your problem there, but I think you need to think seriously about the scope of your listener functions and what they should be attached to.

Also characterButton is global, not local. It should be local.

The answer to the question on line 74 is no. Also, destroy() does not receive a did phase.

Lines 43 and 44 you are adding a button to the scene’s group but also adding it to something else. I don’t know what that other thing is doing, but the chances are that it is holding onto the button even after the scene has been destroyed, which will have unpredictable consequences. I have to say, if you are using an external library to position objects on your screen, I highly recommend giving it the scene group and not individual objects. You do not want display objects being held in memory by something which has nothing to do with the life cycle of the scene’s own display group.

The first code works now to get to the sub-menu and then the call back from the sub-menu successfully recalls the menu (first code file). Once back to the main menu I still am unable to get the main menu to respond to a button click event. I am now receiving an error message, something I was not receiving before. Here it is:
addEventListener: listener cannot be nil: nil

stack traceback: in function ‘error’

?:in function ‘gotoScene’

menu.lua:118: in function ‘_onRelease’

This is happening when I attempt to call the sub-menu again. In the :show() function I am removing the menu scene. Should this be done in the target sub-menu?

Here is the corrected first code file:

[lua] ----------------------------------------------------------------------------------------- -- -- menu.lua -- ----------------------------------------------------------------------------------------- local composer = require('composer') -- Scene management local scene = composer.newScene() local controller = require('libs.controller') -- Gamepad support --local relayout = require('libs.relayout') -- Repositions elements on screen on window resize -- include Corona's "widget" library local widget = require ('widget') -- Buttons ----------------------------------------------------------------------------------------- -- MAIN MENU ----------------------------------------------------------------------------------------- function scene:create()     local \_W, \_H, \_CX, \_CY = relayout.\_W, relayout.\_H, relayout.\_CX, relayout.\_CY     --local calledScene = nil     local group = self.view     -- MENU IMAGE, 'buttons' ARE TRANSPERANT OVER EXISTING ACTION LABELS IN JPG       local backGroundImage1 = 'images/backgrounds/mainMenuScreen.jpg'     local backGround = display.newImageRect(backGroundImage1,1920, 1200)           backGround.x = display.contentCenterX           backGround.y = display.contentCenterY     --relayout.add(backGround)        local function onCharacterTouch(event)     if "began" == event.phase then       composer.gotoScene( "scenes.character\_forum", "fade", 1500)       return true     end   end         --SET BUTTON THAT WILL CALL NEXT MENU SCENE   local characterButton = widget.newButton({       width = 300,       height = 50,       x = display.contentCenterX,       y = 600,       onEvent = onCharacterTouch       })          group:insert(characterButton)     --relayout.add(characterButton)   end function scene:show(event)   local group = self.view     print("in show", parent)     if "did" == event.phase then       -- IS THIS MISPLACED?       print("show, removing menu scene")       composer.removeScene("menu")     end      end function scene:hide( event )     local sceneGroup = self.view     local phase = event.phase     if ( phase == "did" ) then     end end    -- Called when scene is about to move offscreen: function scene:exit( event )     local group = self.view          -- INSERT code here (e.g. stop timers, remove listenets, unload sounds, etc.) end -- If scene's view is removed, scene:destroyScene() will be called just prior to: function scene:destroy( event )     local group = self.view     local shouldRecycle = true     if characterButton then        characterButton:removeSelf()    -- widgets must be manually removed     end end ----------------------------------------------------------------------------------------- -- END OF YOUR IMPLEMENTATION ----------------------------------------------------------------------------------------- -- "create" event is dispatched if scene's view does not exist scene:addEventListener( "create" ) -- "enter" event is dispatched whenever scene transition has finished -- is this needed once I return from the called scene 'character\_forum'?? scene:addEventListener( "show" ) scene:addEventListener( "hide" ) -- "exit" event is dispatched whenever before next scene's transition begins scene:addEventListener( "exit" ) -- "destroy" event is dispatched before view is unloaded, which can be -- automatically unloaded in low memory situations, or explicitly via a call to -- storyboard.purgeScene() or storyboard.removeScene(). scene:addEventListener( "destroy" ) ----------------------------------------------------------------------------------------- return scene [/lua]

second code file has had the button declaration and the associated listener set to local.

thank for the help after closely reviewing the code I found several things wrong. Declarations for the listener functions inside create() that

should have been in global above create(). items missing from  the sceneGroup. Amazing it functioned as far as it did. Well new stuff, new lessons. Again thanks for the help.

In your first code file, within the :create() function, you have function onCharacterTouch(event) which is global. It shouldn’t be.

I’m not saying that’s your problem there, but I think you need to think seriously about the scope of your listener functions and what they should be attached to.

Also characterButton is global, not local. It should be local.

The answer to the question on line 74 is no. Also, destroy() does not receive a did phase.

Lines 43 and 44 you are adding a button to the scene’s group but also adding it to something else. I don’t know what that other thing is doing, but the chances are that it is holding onto the button even after the scene has been destroyed, which will have unpredictable consequences. I have to say, if you are using an external library to position objects on your screen, I highly recommend giving it the scene group and not individual objects. You do not want display objects being held in memory by something which has nothing to do with the life cycle of the scene’s own display group.

The first code works now to get to the sub-menu and then the call back from the sub-menu successfully recalls the menu (first code file). Once back to the main menu I still am unable to get the main menu to respond to a button click event. I am now receiving an error message, something I was not receiving before. Here it is:
addEventListener: listener cannot be nil: nil

stack traceback: in function ‘error’

?:in function ‘gotoScene’

menu.lua:118: in function ‘_onRelease’

This is happening when I attempt to call the sub-menu again. In the :show() function I am removing the menu scene. Should this be done in the target sub-menu?

Here is the corrected first code file:

[lua] ----------------------------------------------------------------------------------------- -- -- menu.lua -- ----------------------------------------------------------------------------------------- local composer = require('composer') -- Scene management local scene = composer.newScene() local controller = require('libs.controller') -- Gamepad support --local relayout = require('libs.relayout') -- Repositions elements on screen on window resize -- include Corona's "widget" library local widget = require ('widget') -- Buttons ----------------------------------------------------------------------------------------- -- MAIN MENU ----------------------------------------------------------------------------------------- function scene:create()     local \_W, \_H, \_CX, \_CY = relayout.\_W, relayout.\_H, relayout.\_CX, relayout.\_CY     --local calledScene = nil     local group = self.view     -- MENU IMAGE, 'buttons' ARE TRANSPERANT OVER EXISTING ACTION LABELS IN JPG       local backGroundImage1 = 'images/backgrounds/mainMenuScreen.jpg'     local backGround = display.newImageRect(backGroundImage1,1920, 1200)           backGround.x = display.contentCenterX           backGround.y = display.contentCenterY     --relayout.add(backGround)        local function onCharacterTouch(event)     if "began" == event.phase then       composer.gotoScene( "scenes.character\_forum", "fade", 1500)       return true     end   end         --SET BUTTON THAT WILL CALL NEXT MENU SCENE   local characterButton = widget.newButton({       width = 300,       height = 50,       x = display.contentCenterX,       y = 600,       onEvent = onCharacterTouch       })          group:insert(characterButton)     --relayout.add(characterButton)   end function scene:show(event)   local group = self.view     print("in show", parent)     if "did" == event.phase then       -- IS THIS MISPLACED?       print("show, removing menu scene")       composer.removeScene("menu")     end      end function scene:hide( event )     local sceneGroup = self.view     local phase = event.phase     if ( phase == "did" ) then     end end    -- Called when scene is about to move offscreen: function scene:exit( event )     local group = self.view          -- INSERT code here (e.g. stop timers, remove listenets, unload sounds, etc.) end -- If scene's view is removed, scene:destroyScene() will be called just prior to: function scene:destroy( event )     local group = self.view     local shouldRecycle = true     if characterButton then        characterButton:removeSelf()    -- widgets must be manually removed     end end ----------------------------------------------------------------------------------------- -- END OF YOUR IMPLEMENTATION ----------------------------------------------------------------------------------------- -- "create" event is dispatched if scene's view does not exist scene:addEventListener( "create" ) -- "enter" event is dispatched whenever scene transition has finished -- is this needed once I return from the called scene 'character\_forum'?? scene:addEventListener( "show" ) scene:addEventListener( "hide" ) -- "exit" event is dispatched whenever before next scene's transition begins scene:addEventListener( "exit" ) -- "destroy" event is dispatched before view is unloaded, which can be -- automatically unloaded in low memory situations, or explicitly via a call to -- storyboard.purgeScene() or storyboard.removeScene(). scene:addEventListener( "destroy" ) ----------------------------------------------------------------------------------------- return scene [/lua]

second code file has had the button declaration and the associated listener set to local.

thank for the help after closely reviewing the code I found several things wrong. Declarations for the listener functions inside create() that

should have been in global above create(). items missing from  the sceneGroup. Amazing it functioned as far as it did. Well new stuff, new lessons. Again thanks for the help.