SKScene does not auto-update when returning to previous scene

I am attempting to write a game in Swift using SpriteKit, and I have a number of different scenes that I switch back and forth between frequently. I have recently implemented a "standard" app-wide way of doing so, using a singleton SceneManager which (for now) remembers the most recent Scene and can switch back to it.


Unfortunately, for reasons I do not yet understand, while it switches back to the previous scene successfully, it does not also update the view to display the scene I have just switched back to—it continues to display the scene it was on until I click in the window.


As I am able to switch tothese scenes initially without any problem, and they operate perfectly normally once the mouse click has reminded the app that it actually needs to update the screen, I am not sure what I am doing wrong here.


Here is the method that attempts to return to the previously-displayed scene:

  func returnToPreviousScene() {
       if self.backgroundNode != nil {
            self.backgroundNode = nil
       }
       var log = "Returning to scene..."
       if let oldScene = self.scene {
            log += "Current scene: \(oldScene.sceneName)"
            oldScene.removeFromParent()
       }
       if let scene = self.previousScene {
       self.scene = scene
       scene.isPaused = true
       NSLog("Presenting old scene now")
       self.view.presentScene(nil)
       self.view.presentScene(scene)
       self.view.window!.makeFirstResponder(scene)
       scene.isPaused = false
     
       self.returnControl()

       self.previousScene = nil
       } else {
            log += "no current scene (?!)"
       }

       if let partyScene = self.scene as? TGPartyScene {
            self.partyNode = partyScene.partyNode
       } else {
       self.partyNode = nil
       }
       NSLog("\(log); changed back to scene \(self.currentSceneName())")
  }


Any assistance would be most appreciated.


Timothy Collett

Replies

You could just use the standard user defaults to remember a simple string name, like the previous scene file. I just don't think I'd take the singleton approach if thats all you're trying to do. Are you trying to save state in the old scene to return to it? For example, like your character killed enemies in one room of castle, and you want those enemies to stay dead.


Anyway, keep in mind, I dont have the full picture, but I'd scrap a lot of that code....


I've never seen .removeFromParent called on a scene before. Don't think that does anything.


presentScene(nil) then immediately calling self.view.presentScene(scene) , makes me go "huh?"


I think you're always better off transitioning in and out of your scenes from your current one. Sprite Kit is working its own magic to do that in the best way possible, for example, and I'd be worried trying to do that with a singleton of your own is going to cause more issues than its worth.

I absolutely agree that the unnecessary parts of the code should be removed. This includes (especially) lines 8, 12, 14, 16 and 17. Regarding possible reasons why the scene freezes, some things to check:


a. Make sure that returnToPreviousScene is being called on the main thread. Doing it on a background thread could easily cause the sort of problems described.


b. It's certainly possible that a scene node is a child of an object of a private type (private to Sprite Kit, I mean). "removeFromParent" seems like a really bad idea, if it's not undoing an earlier "addChild" in the OP's code.


c. In spite of the OP's description of "a number of different scenes that I switch back and forth between frequently", this code isn't that. Since it never sets "previousScene" to a non-nil value, and it seems to throw away the reference to the current scene irretrievably at line 15, I assume this is not the real code, or there is more code elsewhere that's involved in the scene management. This makes me wonder if the problem is in the place where the OP is looking.

Thank you for your replies so far.


CartoonSmart.com, I am considering switching to simply re-creating the scenes on demand, as they are fairly static thus far. However, I would very much like to understand what is causing this behaviour so that I can avoid it in future, if I end up with scenes that do require more state be saved to be usable.


QuinceyMorris, aside from line 16 (which I am pretty sure I need, but haven't tested recently), the lines of code you mention are all lines that were added specifically to attempt to debug the issue I have described.


a) Is keyDown() called on a background thread? I fear I do not recall offhand, but that's where returnToPreviousScene() is being called from.


b) As I said, I only added that in hopes of fixing this issue, and have already removed it (I wanted to present the most current version of the code when pasting it in before).


c) Yes, as should be fairly clear, this is merely the method in which the current scene should be being removed and replaced with the previous one.


Here is the full SceneManager class (link broken up due to advice on avoiding perma-moderation): (topazgryphon.org/ ~tcollett /SceneManager.swift), with the aforementioned extraneous lines removed. (Noting that TGScene, etc, are simply my own subclasses of the relevant SK* classes, while TGSceneDelegate is a protocol defining methods for passing keyboard control around between scenes and nodes.)


Timothy Collett

I had the same problem. I fixed it by using presentScene(nextScene, transition: .fade(withDuration: 0)) instead of just presentScene(nextScene)