0 Replies
      Latest reply on Jan 11, 2020 3:10 PM by igorland
      igorland Level 1 Level 1 (0 points)

        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!