Problem with the position of multiple SKShapeNodes on rotation

Hi. I have faced a problem in a seemingly easy situation. I am using SpriteKit to present several boxes (SKShapeNodes) with texts inside (similar to a messaging app). The boxes are created just nice. However, when I rotate the device, the lowest and the second to lowest boxes are placed as expected, then the next box is located higher (by the height of the box), the other one is placed even higher (I wish I could attach screenshots).


This is my code.


ViewController


class GameViewController: UIViewController {
    override func viewDidLoad()
       {
           super.viewDidLoad()

           let scene = GameScene()
           let skView = self.view as! SKView
       
           if skView.bounds.size.height>skView.bounds.size.width { scene.size = CGSize(width: 1080, height: 1920) }
           else { scene.size = CGSize(width: 1920, height: 1080) }
       
           skView.showsFPS = true
           skView.showsNodeCount = true
           skView.ignoresSiblingOrder = false
           scene.scaleMode = .aspectFit
           skView.presentScene(scene)
       }

       override func viewWillLayoutSubviews()
       {
           super.viewDidLayoutSubviews()
           let skView = self.view as! SKView
       
           if let scene = skView.scene
           {
               if skView.bounds.size.height>skView.bounds.size.width
               {
                   scene.size = CGSize(width: 1080, height: 1920)
               }
               else
               {
                   scene.size = CGSize(width: 1920, height: 1080)
               }

               var size = scene.size
           
               let boundWidth = skView.bounds.width
               let boundHeight = skView.bounds.height
           
               let newHeight = boundHeight*size.width/boundWidth
               let newWidth = boundWidth*size.height/boundHeight
           
               if newHeight > size.height
               {
                   size.height = newHeight
                   scene.size = size
               }
           
               if newWidth > size.width
               {
                   size.width = newWidth
                   scene.size = size
               }
           }
       }
}

GameScene:


import SpriteKit
import GameplayKit

struct TextMessage: Equatable
{
    var messageText : SKLabelNode?
    var messageBox : SKShapeNode?
}

class GameScene: SKScene {
    var background : SKSpriteNode!
    private var label : SKLabelNode?
    private var spinnyNode : SKShapeNode?
    var listOfTextMessages = [TextMessage]()
    var number = 1

    override func didMove(to view: SKView)
    {
        background = SKSpriteNode()
        background.color = .green
        addChild(background)
    }
 
    override func touchesEnded(_ touches: Set, with event: UIEvent?) {
        switch number {
        case 1:
            createTextMessageBox(text:"wwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww")
        case 2:
            createTextMessageBox(text:"\(number)\(number)\(number)")
        case 3:
            createTextMessageBox(text:"eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee")
        case 4:
            createTextMessageBox(text:"rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr")
        case 5:
            createTextMessageBox(text:"\(number)\(number)\(number)")
        default:
            createTextMessageBox(text:"yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy")
        }

        number += 1
    }

    func createTextMessageBox(text:String)
    {
        // Width of the textbox is fixed and depends on the device position
        var textboxWidth : CGFloat = 500
     
        if UIDevice.current.orientation.isLandscape { textboxWidth = 800 }
        else { textboxWidth = 500 }
      
        // Create the text message label
        let notificationText = SKLabelNode(fontNamed: "AppleSDGothicNeo-Regular")
        notificationText.name = "message_text"
        notificationText.text = text
        notificationText.fontSize = 45
        notificationText.fontColor = SKColor.white
        notificationText.alpha = 0
        notificationText.numberOfLines = 0
        notificationText.horizontalAlignmentMode = .left
        notificationText.verticalAlignmentMode = .center
        notificationText.preferredMaxLayoutWidth = textboxWidth-50

        // Height of the textbox depends on the size of the text
        let textboxHeight = notificationText.frame.height + 50
         
        // Notification textbox that contains the text
        let rightEdgeX = self.convert(CGPoint(x: self.frame.maxX, y: 0), to: background).x
        let bottomEdgeY = self.convert(CGPoint(x: 0, y: self.frame.minY), to: background).y
        let boxPositionX = rightEdgeX-50-textboxWidth
        let boxPositionY : CGFloat = bottomEdgeY+100
     
        // Create the Notification Textbox
        let notificationNode = SKShapeNode(rect: CGRect(x: boxPositionX,y: boxPositionY,width: textboxWidth,height: textboxHeight), cornerRadius: 20)
        notificationNode.name = "message_box"
        notificationNode.fillColor = UIColor(red: 120/255, green: 0/255, blue: 0/255, alpha: 0.8)
        notificationNode.strokeColor = UIColor(red: 128/255, green: 0/255, blue: 0/255, alpha: 1)
        notificationNode.lineWidth = 2
        notificationNode.alpha = 0
        //notificationNode.zPosition = 0
         
        // Position text in the middle of the texbox
        notificationText.position = CGPoint(x: notificationNode.frame.minX+25, y: notificationNode.frame.maxY-textboxHeight/2)
         
        // Add nodes to the scene
        background.addChild(notificationNode)
        notificationNode.addChild(notificationText)
     
        // Add to the list of text messages
        let currentMessage = TextMessage(messageText: notificationText, messageBox: notificationNode)
        listOfTextMessages.insert(currentMessage, at: 0)
     
        // The first message is shown at the bottom, whereas the older messages are moved on top of it.
        for (index,textBox) in listOfTextMessages.enumerated()
        {
            // The latest message
            if index == 0
            {
                let actionBoxFadeIn = SKAction.fadeAlpha(to: 0.8, duration: 0.2) // Fade in the textbox
                let actionTextFadeIn = SKAction.run { textBox.messageText!.run(SKAction.fadeIn(withDuration: 0.2)) }
                let actionMoveGroup = SKAction.group([actionBoxFadeIn,actionTextFadeIn])
                textBox.messageBox!.run(actionMoveGroup)
            }
            else
            {
                textBox.messageBox!.position.y += listOfTextMessages[0].messageBox!.frame.height
            }
        }
    }
 

    override func didChangeSize(_ oldSize: CGSize)
    {
        super.didChangeSize(oldSize)
        var zPosition : CGFloat = 10
     
        if background != nil
        {
            background.size = CGSize(width: self.frame.width, height: self.frame.height)
            background.position = CGPoint(x: self.frame.width/2, y: self.frame.height/2)
        }

        if self.view != nil && !listOfTextMessages.isEmpty
        {
         
            let textboxWidth : CGFloat = UIDevice.current.orientation.isLandscape ? 800 : 500
            let textlabelWidth = textboxWidth-50
            for (index,textBox) in listOfTextMessages.enumerated()
            {
                textBox.messageBox!.zPosition = zPosition
                zPosition += 1
                textBox.messageText!.fontSize = 45
                textBox.messageText!.fontColor = SKColor.white
                textBox.messageText!.numberOfLines = 0
                textBox.messageText!.horizontalAlignmentMode = .left
                textBox.messageText!.verticalAlignmentMode = .center
                textBox.messageText!.preferredMaxLayoutWidth = textlabelWidth
             
                let textboxHeight = textBox.messageText!.frame.height + 50
                let rightEdgeX = self.convert(CGPoint(x: self.frame.maxX, y: 0), to: background).x
                let boxPositionX = rightEdgeX-50-textboxWidth

                let boxPositionY : CGFloat = {
                        return (index == 0) ? self.convert(CGPoint(x: 0, y: self.frame.minY), to: background).y : listOfTextMessages[index-1].messageBox!.frame.minY
                }()

                textBox.messageBox!.path = UIBezierPath(roundedRect: CGRect(x: boxPositionX, y: boxPositionY, width: textboxWidth, height: textboxHeight), cornerRadius: 20).cgPath
                textBox.messageText!.position = CGPoint(x: textBox.messageBox!.frame.minX+25, y: textBox.messageBox!.frame.minY+textboxHeight/2)
            }
        }
    }

The text is also shifted upwards.


Interesting enough, if I do the following (create each box in the array using the coordinates of the first box), the boxes are placed right on top of each other; however, their position is also skewed when their height varies:


let boxPositionY : CGFloat = {
           return self.convert(CGPoint(x: 0, y: self.frame.minY), to: background).y
                }()

textBox.messageText!.position = CGPoint(x: listOfTextMessages[0].messageBox!.frame.minX+25, y: listOfTextMessages[0].messageBox!.frame.minY+textboxHeight/2)


Could someone please help me find the culprit?


Thanks a lot!

Problem with the position of multiple SKShapeNodes on rotation
 
 
Q