sprite-kittransitionsksceneskview

SKView presentScene fails with transition


I'm having what appears to be a problem similar to the one posted here: In SpriteKit presentScene Transition, won't work. However, presentScene does, however the source of the problem (switching from one VC to another) doesn't seem to apply.

Here's the relevant code from my GameViewController, which splits the screen between two views: a UIView "HUD" -occupying the top eighth of the screen- and an SKView "gamePlayView", occupying the remaining space. The controller will first present a MenuScene in gamePlayView (this works fine), which will have buttons with options to either play the game or go to the settings (will possible future options to be added). So far I've just got the start button, which uses a delegate to call the "startNewRound" function of GameViewController.

The plan is for GameViewController to keep a reference to a MenuScene, a DiatonicIntervalScene (the game), and -in future- a SettingsScene, which it will swap in and out of the gamePlayView. All of these are type GameScene, which inherits from SKScene, and does nothing else except prove a reference to GameViewController and some colour values.

// Views
var hud: HUD!
var gamePlayView: SKView!

// Scenes
var menuScene: GameScene!
var gamePlayScene: (GameScene & TurnScene)!

override func viewDidLoad() {

    // There's some code here to determine the respective sizes of 
    // the areas and to create and add them

    self.view.addSubview(hud)
    self.view.addSubview(gamePlayView)

    menuScene = MenuScene(size: gamePlayView.frame.size)
    menuScene.gameController = self

    gamePlayScene = DiatonicIntervalScene(size: gamePlayView.frame.size)
    gamePlayScene.gameController = self

    gamePlayView.presentScene(menuScene)
}

func startNewRound() {

    print("BEFORE: gamePlayView.scene.name = \( gamePlayView.scene!.name!)\n")

    loadNewTurn()

    let reveal = SKTransition.reveal(with: .down,
                                     duration: 1)
    gamePlayView.presentScene(gamePlayScene)
    // gamePlayView.presentScene(gamePlayScene, transition: reveal)

    print("AFTER: gamePlayView.scene.name = \(gamePlayView.scene!.name!)")
}

The problem I'm running into is that this code works exactly as I want it to, unless I attempt to add a transition to gamePlayView.presentScene (you can see the modified, commented out line in "startNewRound()"). If I use that line instead, the transition never happens, and gamePlayView's scene property is never updated.

With no transition, the print statements in startNewRound() print out:

BEFORE gamePlayView.scene.name = Menu
AFTER gamePlayView.scene.name = GameScene

whereas if I use the presentScene which includes the transition, the output is

BEFORE gamePlayView.scene.name = Menu
AFTER gamePlayView.scene.name = Menu

It's nothing to do with loadNewTurn(), I've tried commenting it out (even I didn't think it would do anything). Strange as well is that gamePlayScene's didMoveTo() gets called, despite the fact that the transition doesn't happen and the scene doesn't appear

That's all I can think of to include, thanks for taking time to look at it and let me know if I'm missing anything!

UPDATE: I've discovered that the scene change and transition go as planned if I replace gamePlayView's previous initiliazer:

gamePlayView = SKView(frame: CGRect(origin: gamePlayAreaOrigin, size: gamePlayAreaSize))
self.view.addSubview(gamePlayView)

with:

gamePlayView = self.view as! SKView

making it take up the whole screen, so apparently something about being the view controller's subview instead of it's self.view makes the transition not work


Solution

  • The solution I've stumbled across (in part thanks to this question) is to override my viewcontroller's loadView() and insert the following line

        self.view = UIView(frame: UIScreen.main.bounds)
    

    This appears to cause everything else to fall into place. The transition now works as expected and intended, and there are not -as of yet- any unintended consequences!