1

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

  • You are printing too early, transition is an animation, so of course you are still going to print the old scene until you hit the point of animation that the swap happens – Knight0fDragon Apr 20 '18 at 19:47
  • your transition is not happening because something is in a paused state, my guess is your gamescene, set the isPaused = false – Knight0fDragon Apr 20 '18 at 19:49
  • Hey @Knight0fDragon, thanks! I tried adding "gamePlayScene.isPaused = false" and "menuScene.isPaused = false" immediately after presentScene(), and as well in the didMoveTo() of DiatonicIntervalScene() (in the form of "self.isPaused = false"). Unfortunately, it hasn't seemed to have any effect. – William Millington Apr 20 '18 at 20:55
  • Play around with it, Apple loves screwing with the pause state, so you may have to unpause it again in didmoveto(view:) – Knight0fDragon Apr 20 '18 at 20:57
  • I tried overriding the `didMoveTo(view:)` of gamePlayScene (DiatonicIntervalScene) to put in `self.paused = false`, and found that when I printed out `view.scene.name` from there, it's still giving me "Menu" – William Millington Apr 24 '18 at 14:32
  • your print is always going to say menu, because your swap is not immediate – Knight0fDragon Apr 24 '18 at 14:33
  • so I am looking at your code here, i see a lot of mistakes going on. Your gameplay view is a subview of what? – Knight0fDragon Apr 24 '18 at 14:41
  • send me your code (knight0fdragon@gmail.com), I will clean it up for you and teach you the right way to do sprite kit outside of SO so that we are not flooding the comments – Knight0fDragon Apr 24 '18 at 14:42
  • Hey, I've found the solution I was looking for, but thanks for the offer! (I did leave out some code that might have made it that last point clearer, sorry about that) – William Millington Apr 24 '18 at 16:28
  • Your code flow is still wrong, you are going to encounter more problems – Knight0fDragon Apr 24 '18 at 16:31

1 Answers1

0

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!