Repositioning on new orientatation

I am really struggling to get sprites to rearrange themselves when the device is orientated from portrait to landscape and vice-vera. I have the following check on the ViewController:

    override func didRotate(from fromInterfaceOrientation: UIInterfaceOrientation) {
        
        let test1 = Menu()
        switch UIDevice.current.orientation{
        case .portrait              : test1.setUpScene()
        case .portraitUpsideDown    : test1.setUpScene()
        case .landscapeLeft         : test1.setUpScene()
        case .landscapeRight        : test1.setUpScene()
        default: break
        }
    }

This then launches the same checks as when the page is loaded, but none of the expected changes are made:

let backButtonPositionPortrait = CGPoint(x: ScreenSize.width * -0.4, y: ScreenSize.height * 0.40)
let backButtonPositionLandscape = CGPoint(x: ScreenSize.width * -0.4, y: ScreenSize.height * -0.20)

func setUpScene() {
    if UIDevice.current.orientation == .portrait {
        print("I'M IN PORTRAIT RIGHT NOW")
        backButton.position = backButtonPositionPortrait
        addChild(backButton)
    }
    if UIDevice.current.orientation == .landscapeLeft || UIDevice.current.orientation == .landscapeRight {
        print("I'M IN LANDSCAPE RIGHT NOW")
        backButton.position = backButtonPositionLandscape
        addChild(backButton)
    }
}

When the scene first loads the backButton is placed accordingly, on both orientations, but only before entering the scene. When I orientate to the opposite the expected behaviour is that the sprites should move as I placed them, but they seem to only respect the screen dimensions the scene began with and so the sprites end up out of view.

I think I need to look into override func willRotateToInterfaceOrientation and re-invigorate the bounds to recalibrate for the new orientation, but I am not sure what to do about it?

I think the problem is you are storing sizes at startup in backButtonPositionPortrait and backButtonPositionLandscape, They probably need to be recalculated whenever used in case ScreenSize changes. E.g.

var backButtonPositionPortrait: CGPoint {
    return CGPoint(x: ScreenSize.width * -0.4, y: ScreenSize.height * 0.40)
}

var backButtonPositionLandscape: CGPoint {
    return CGPoint(x: ScreenSize.width * -0.4, y: ScreenSize.height * -0.20)
}

If you are using Swift 5.1 the return is optional.

Thanks for your reply, but it didn't make any difference.

I think the issue is more profound and dug up an old article on the issue from 2014 (so I'm unsure if it's still relevant) but seems to be an issue with the viewDidLoad in the ViewController, recommending a substitution with viewWillLayoutSubviews instead to get the new values when rotating.

Presently it just redirects to the main menu every time I rotate the device for some reason, so I'll have to keep looking at the matter.

ref: https://web.archive.org/web/20160925093923/http://www.ymc.ch/en/ios-7-sprite-kit-setting-up-correct-scene-dimensions

In the end I had to do it the hard way (I am used to it in SpriteKit now) and used a series of logic gates before executing on a switch statement to arrange every node.

I found netshark1000's contributions on a StackOverflow posting really helpful as there was no built in Apple solution to getting info on the model of device in use: https://stackoverflow.com/questions/26028918/how-to-determine-the-current-iphone-device-model

I don't know why Apple doesn't have something like this built into Swift, it seems like they really should have:

switch UIDevice().type {
iPhone5, iPhone5S, iPhone5C, iPhoneSE : // 320 x 568pt | 640 × 1136px
iPhone6, iPhone6S, iPhone7, iPhone8 : // 375 x 667pt | 750 × 1334px
iPhone6Plus, iPhone6SPlus, iPhone7Plus, iPhone8Plus : // 414 x 736pt | 1242 × 2208px
iPhoneX, iPhoneXS, iPhone11Pro : // 375 x 812pt | 1125 × 2436px
iPhoneXR, iPhoneXSMax, iPhone11, iPhone11ProMax : // 414 x 896pt | 1242 × 2688px
iPadMini4, iPadMini5, iPad5, iPad6, iPadAir2, iPadPro9_7 : // 768 x 1024pt | 1536 × 2048px
iPadAir3, iPadPro10_5 : // 834 x 1112pt | 1668 × 2224px
iPadPro11 : // 834 x 1194pt | 1668 × 2388px
iPadPro12_9, iPadPro2_12_9, iPadPro3_12_9 : // 1024 x 1366pt | 2048 × 2732px
}

As you can see, there are a lot of screen sizes, but mercifully some do overlap. UIDevice.current.orientation.isLandscape / isPortrait doubled my workload, and in the end I locked the orientation as the screen will just not organise sprites if freely rotated (I still have the original problem).

I also needed more granular control when in landscape as my sprites were too cramped compared to portrait, which made a lot more work necessary as they would need to be substituted as can't scale my sprites without a noticeable visual loss in quality.

However, this does give me granular control and it did "work", but the orientation must be locked, which is a shame, but nobody seems to know how to allow for sprites to reorganise themselves after rotation. The closest I saw was on the pause menu in CrossyRoad, but they used a trick that kept everything compact enough in either rotation.

Terms of Service

Privacy Policy

Cookie Policy