I get black screen after several switches to other scene [SOLVED]

When I press play button or exit button more than 1 time and don’t wait until transition finishes I am getting black screen… Any ideas to fix that?
And if I wait until transition finishes and only then press the button everything is good, until I do it for about 10 times and then black screen comes.

Code:

  local playButton = display.newSprite(sceneGroup,playSheet,sq)
  playButton:scale( 1.5, 1.5 )
  playButton.x = right - 70
  playButton.y = bottom - 40

  local function Play(event)
    if(event.phase == "began") then
      if playerLevel == 0 then
        local options =
        {
        effect = "crossFade",
        time = 1000
        }
        storyL = 1
        timer.performWithDelay(1500, function() playButton:addEventListener("touch",Play) end)
        composer.gotoScene("scenes.SpaceMap",options)
        composer.gotoScene("scenes.story",options)

      else
        local options =
        {
        effect = "fromRight",
        time = 1000
        }

        playButton:removeEventListener("touch", Play)
        timer.performWithDelay(1500, function() playButton:addEventListener("touch",Play) end)
        composer.gotoScene("scenes.SpaceMap",options)
      end
    end
  end

  playButton:addEventListener("touch", Play)

-- Other scene

local backButton = display.newSprite(sceneGroup,playSheet,sq)
  backButton:setSequence("back")
  backButton.x = left + 40
  backButton.y = top + 40
  backButton:scale(0.7,0.7)

  local function back()
    local options =
    {
    effect = "fromLeft",
    time = 1000
    }
    backButton:removeEventListener("touch",back)
    timer.performWithDelay(1500, function() backButton:addEventListener("touch",back) end)
    composer.gotoScene("scenes.lobby", options)
  end

  backButton:addEventListener("touch",back)

Video:

I have some solutions that you can try, but first - why do you “gotoscene” twice? line after line:
composer.gotoScene("scenes.SpaceMap",options) composer.gotoScene("scenes.story",options)

Anyway,
solution 1:
you can try to remove the old scene from the screen before you go to the next one:
composer.removeScene( "scene1" )
I think you create a scene over scene over the scene and it crashes after a while - so this solution might help.
When you do that, you destroy all the object’s listeners on the screen and they cause you problems as well.

Solution 2:
I’m not sure if it will work, but you can try it:
You can cancel the transition when you click on one of the buttons, cancel it before you start the new transition - just add the line
transition.cancel()

Solution 3:
Block the click on the buttons until the transition is over (you can create a global boolean variable that is false until the scene ends loading).

Summary:
I think the problem happens because you don’t clean up your screen when you move from one scene to another - and after a while it cause weird behaviors because you duplicate listeners and objects…

1 Like

The problem is timer.performWithDelay(1500, function() playButton:addEventListener("touch",Play) end). you are adding multiple listeners to the button.

1 Like

whoops, these are my mistake

composer.gotoScene("scenes.SpaceMap",options) 
composer.gotoScene("scenes.story",options)

I tried it it doesn’t seem to work…

Ok, it looks like 1 soliution fixed everything. But now I have that black when sliding animation happens.
I don’t know how to explain it so I made a video:

Should I make some snapshot or how is it called to replace last scene so it looks like it was, but without that bug?

When playerLevel is 0 and you click the playButton, you are adding a new touch listener to it without removing the old one. You need to remove the old one like you do in the else branch. Since you need to remove it either way, you can just use playButton:removeEventListener once before “if playerLevel == 0”. Was that your solution?
Not sure why you’re getting the black screen when switching scenes. Maybe something to do with calling composer.goToScene twice at the same time? I haven’t used composer in a long time, but I imagine that would be problematic. What exactly is it you are trying to achieve with that?

1 Like

oh, I checked my code and it looks like what my previous method had typos. I will try to use my old method without these typos, maybe it is working too. Thank you.

my previous method with timers and removing and adding listeners didn’t work at all so I came up with other solution (third) blocking clicks until transition over (@tsoakuo).
For those who have the same issue:
In your show funcion set variable:

function scene:show(event)
  if event.phase == "did" then -- important

    curScene = "lobby" -- anything u want it can be scene name

  end
end

Then in same scene in your function add this:

local function Play(event)
    if(event.phase == "began") then
      if curScene == "lobby" then -- <-- this line
          local options =
          {
            effect = "slideLeft",
            time = 1000
          }

          curScene = "transition" -- block button
          composer.gotoScene("scenes.SpaceMap",options)
          --composer.removeScene( "scenes.lobby" )
      end
    end
  end

In other scene do:
Show function:

function scene:show(event)
  if event.phase == "did" then -- important

    curScene = "map" -- not the same like in last scene

  end
end

Then function:

local function back(event)
    if event.phase == "began" then
      if curScene == "map" then
        local options =
        {
          effect = "slideRight",
          time = 1000
        }

        curScene = "transition" -- block button
        composer.gotoScene("scenes.lobby", options)
      end
    end
  end

And thanks for everyone who helped me :smiley:

Personally, I’d just add the listener on the scene’s “show” event and remove it in the “hide”
event:

-- main.lua
    local composer = require "composer"
    composer.gotoScene("lobby")

_

-- lobby.lua
local composer = require( "composer" )
local scene = composer.newScene()

local bg, playButton
local function onPlay()
	composer.gotoScene("spacemap", {effect = "fromLeft", time = 1000})
end


function scene:create( event )
	local sceneGroup = self.view
	bg = display.newRect(display.contentCenterX, display.contentCenterY, display.contentWidth, display.contentHeight)
	bg:setFillColor(0,0,0.5)
	playButton = display.newRect(display.contentCenterX, display.contentCenterY, 100, 50)
	sceneGroup:insert( bg )
	sceneGroup:insert( playButton )
end

function scene:show( event )
	local phase = event.phase
	if phase == "did" then
		playButton:addEventListener("tap", onPlay)
	end	
end

function scene:hide( event )
	local phase = event.phase
	if event.phase == "will" then
		playButton:removeEventListener("tap", onPlay)
	end
end

scene:addEventListener( "create", scene )
scene:addEventListener( "show", scene )
scene:addEventListener( "hide", scene )

return scene

_

-- spacemap.lua
local composer = require( "composer" )
local scene = composer.newScene()

local bg, backButton
local function onBack()
	composer.gotoScene("lobby", {effect = "fromRight", time = 1000})
end


function scene:create( event )
	local sceneGroup = self.view
	bg = display.newRect(display.contentCenterX, display.contentCenterY, display.contentWidth, display.contentHeight)
	bg:setFillColor(0,0.5,0)
	backButton = display.newRect(display.screenOriginX + 75, display.screenOriginY + 100, 100, 50)
	sceneGroup:insert( bg )
	sceneGroup:insert( backButton )
end

function scene:show( event )
	local phase = event.phase
	if phase == "did" then
		backButton:addEventListener("tap", onBack)
	end	
end

function scene:hide( event )
	local phase = event.phase
	if event.phase == "will" then
		backButton:removeEventListener("tap", onBack)
	end
end

scene:addEventListener( "create", scene )
scene:addEventListener( "show", scene )
scene:addEventListener( "hide", scene )

return scene
1 Like

Oh, never thought about it, thanks! :sweat_smile:

By far the easiest method is to have a global called canTap and set that to false when the scene transitions (or you want to block user input for a while). Set this back to true once the transition has finished.

In all of your UI, simply check if you can process the touch/tap based on the value of the canTap flag. this way you don’t have to keep adding/removing tap/touch handlers on what might be hundreds of different touch points in an app.

1 Like