Me, Carlos

Coding

New York, NY

03/03/2019



Swift

Extensions

Using extensions can make the life of a programmer much easier.

Here are some extensions that I use regularly.

calculateFrameWithMargins

When I need to create containers, and establish margins, or calculate how much bigger a container should be, to fit something inside of it, I use this function. I noticed I was using SKNode calculateAccumulatedFrame() and then adding margins a lot, so I made this useful function.

createMultilineLabel

Usually I know exactly the width in which I want to fit some text. Even if it is long, I wanted to create a type of label where I just pass a few arguments, and it generates the labels for me. That is what this function does.

clearAllChildren

The last two functions were created to avoid too many lines of coding, and also when a SKNode has many children, it is a quick method to remove them all by the end of an animation.

extension SKNode{

    /** Calculates Accumulated frame of Node + margins defined */
    func calculateFrameWithMargins(height:CGFloat, width:CGFloat) -> CGRect{
        let oldFrame = self.calculateAccumulatedFrame()
        let originX = oldFrame.origin.x - width
        let originY = oldFrame.origin.y - height
        let newWidth = oldFrame.size.width + (2 * width)
        let newHeight = oldFrame.size.height + (2 * height)
        return CGRect(x: originX, y: originY, width: newWidth, height: newHeight)
    }

    func createMultilineLabel(message:String, maxWidth:CGFloat, fontSize:CGFloat, aligned:SKLabelHorizontalAlignmentMode){

        let mainLabel = SKLabelNode(fontNamed: GameFontNames.inconsolata)
        mainLabel.fontSize = fontSize
        mainLabel.horizontalAlignmentMode = aligned
        mainLabel.verticalAlignmentMode = .top
        mainLabel.color = SKColor.lightGray

        let tArray = message.components(separatedBy: " ")

        var lastFittingLabel:SKLabelNode = mainLabel.copy() as! SKLabelNode
        lastFittingLabel.text = ""

        var builtLabels:[SKLabelNode] = []
        var lblPosY:CGFloat = 0.0

        print("word array")

        for windex in 0...tArray.count - 1{

            let word = tArray[windex]

            let trialLabel:SKLabelNode = lastFittingLabel.copy() as! SKLabelNode

            if let previousText = trialLabel.text{
                  if previousText == "" {
                        trialLabel.text = word
                  }else{
                        trialLabel.text!.append(" \(word)")
                  }
            }else{
                trialLabel.text = word
            }

            let labelWidth = trialLabel.calculateAccumulatedFrame().width

            if labelWidth > maxWidth{

                  // does not fit. Add the last one to the array
                  lastFittingLabel.position = CGPoint(x: 0.0, y: lblPosY)
                  builtLabels.append(lastFittingLabel.copy() as! SKLabelNode)

                  // Update height of next Label
                  let heightChange = lastFittingLabel.calculateAccumulatedFrame().height + 2.0
                  lblPosY -= heightChange

                  // as this word doesn't fit, we need to add it to the next label
                  lastFittingLabel.text = word

                  }else{
                        // does fit. update
                        lastFittingLabel = (trialLabel.copy() as! SKLabelNode)
                  }
                  // Add the last one
                  if windex == tArray.count - 1{
                        lastFittingLabel.position = CGPoint(x: 0.0, y: lblPosY)
                        builtLabels.append(lastFittingLabel)
                  }
              }

              for label in builtLabels{
                    self.addChild(label)
              }
        }

        /** Removes all children */
        func clearAllChildren(){
            // Clear the children
            if self.children.count > 0{
                for child in children{
                    child.removeFromParent()
                }
            }
        }

        /** Removes self from parent */
        func clearFromParent(){
            if let _ = self.parent{
               self.removeFromParent()
            }
        }
    }