Search code examples
swiftsprite-kitsksceneiphone-xs-max

How to change SKScene position before presenting?


I am trying to adjust SKScene position based on the device the game is running. For example due to 'top notch' area of iPhone XS Max, I need to subtract that height from SKScene height and position the scene accordingly.

So here is how I calculate the height aka safeAreaHeight in the AppDelegate and subtract from scene height aka sceneHeight:

    safeAreaHeight = UIApplication.shared.statusBarFrame.size.height
    sceneHeight -= safeAreaHeight

In GameViewController I try to re-position the SKScene like below:

    if let view = self.view as! SKView? {
        // Load the SKScene from 'MainMenuScene.sks'
        if let scene = SKScene(fileNamed: "MainMenuScene") {
            // Set the scale mode to scale to fit the window
            scene.scaleMode = .aspectFit
            scene.size.height = sceneHeight
            scene.size.width = sceneWidth
            scene.position.y -= safeAreaHeight
            // Present the scene
            view.presentScene(scene)
        }

        view.ignoresSiblingOrder = true
        view.showsFPS = true
        view.showsNodeCount = true
    }

However, I am getting below error:

SKScene: Setting the position of a SKScene has no effect.

Additionally, I tried to use SKAction to move position of the SKScene as well, then I received below error:

SKScene: Animating the position of a SKScene has no effect.

Thank you for the help.


Solution

  • Well I figured how to achieve this, I am sharing in case it would help someone else.

    Inside AppDelegate you get the correct safe area values and store it in a singleton (in my case: safeAreaHeight) for access throughout the app. Subtract the amount from scene height (sceneHeight).

        let kWindow = UIApplication.shared.windows[0]
        safeAreaHeight = kWindow.safeAreaInsets.top + kWindow.safeAreaInsets.bottom
        screenHeight = screenRect.size.height - safeAreaHeight
    

    Don't forget the adjust the sceneHeight in GameViewController before presenting it:

        if let view = self.view as! SKView? {
            // Load the SKScene from 'MainMenuScene.sks'
            if let scene = SKScene(fileNamed: "MainMenuScene") {
                // Set the scale mode to scale to fit the window
                scene.scaleMode = .aspectFit
                scene.size.height = sceneHeight
                scene.size.width = sceneWidth
                // Present the scene
                view.presentScene(scene)
            }
    
            view.ignoresSiblingOrder = true
            view.showsFPS = true
            view.showsNodeCount = true
        }
    

    Inside loaded scene, in this case it is MainMenuScene, you simply find subview of SKScene and adjust its Y position by subtracting the safeAreaHeight at its center

        guard let subView = self.view else { return }
        subView.center.y -= safeAreaHeight
    

    PS.: Do not adjust all the views in different scenes (ie.: GameScene, GameOverScene etc.) Once you adjust, it remains throughout the app.