Search code examples
iosswiftsprite-kitskspritenodeskshapenode

How to rotate SKLabelNode in company with its parent SKShapeNode?


enter image description here

When press the screen, balls created with the following codes:

var n = 1
func addBall(_ x:CGFloat){
    let numShape =  SKShapeNode(circleOfRadius: 30)
    numShape.name  = "ball"
    numShape.position = CGPoint(x: x, y: frame.maxY-40)
    numShape.physicsBody = SKPhysicsBody(circleOfRadius: 30)
    numShape.fillColor = SKColor.white
    numShape.physicsBody?.density = 0.1
    numShape.physicsBody?.affectedByGravity = true
    numShape.physicsBody?.friction = 0;
    numShape.physicsBody?.restitution = 0.6
    numShape.physicsBody?.allowsRotation = true
    numShape.physicsBody?.isDynamic = true

    let numLabel = SKLabelNode(fontNamed: "Helvetica")
    numLabel.text = "\(n)"
    numLabel.name = "\(n)"
    numLabel.fontColor = .red
    numLabel.position = CGPoint(x: 0, y: 0)
    numLabel.verticalAlignmentMode = .center

    numShape.addChild(numLabel)
    self.addChild(numShape)

    n += 1
}

The balls can rotate, but their childNode numlabel don't rotate in company with them. I try to update their zRotation like below:

   override func update(_ currentTime: TimeInterval) {
        self.enumerateChildNodes(withName: "ball") {
            node, stop in
            if (node is SKShapeNode) {
                let ball = node as! SKShapeNode
                let num = ball.children[0]
                num.zRotation = ball.zRotation
            }
        }

    }

They still refuse to rotate. If I change zRotation directly like num.zRotation = 2, they work.

How can I make them rotate in company with SKShapeNode?

Thx.


Solution

  • You need to set your friction to a number other than 0.

    Also, concerning the shape node performance:

    look at the draw count at the bottom of 50 shapes:

    enter image description here

    for _ in 1...50 {
      let x = arc4random_uniform(UInt32(frame.maxX));
      let xx = CGFloat(x) - size.width/4
    
      let y = arc4random_uniform(UInt32(frame.maxY))
      let yy = CGFloat(y) - size.width/4
    
      let shape = SKShapeNode(circleOfRadius: 50)
      shape.strokeColor = .blue
      shape.lineWidth = 1
      shape.position = CGPoint(x: xx, y: yy)
      addChild(shape)
    }
    

    But now compare that to this image of only 2 draws with only a few lines of refactoring:

    func addFiftySprites() {
    
      let shape = SKShapeNode(circleOfRadius: 50)
      shape.strokeColor = .blue
      shape.lineWidth = 1
    
      let texture = SKView().texture(from: shape)
    
      for _ in 1...50 {
        let x = arc4random_uniform(UInt32(frame.maxX));
        let xx = CGFloat(x) - size.width/4
    
        let y = arc4random_uniform(UInt32(frame.maxY))
        let yy = CGFloat(y) - size.width/4
    
        let sprite = SKSpriteNode(texture: texture)
        sprite.position = CGPoint(x: xx, y: yy)
    
        addChild(sprite)
      }
    }
    

    enter image description here


    The magic here is using let texture = SKView().texture(from: <SKNode>) to convert the shape to a sprite :) let sprite = SKSpriteNode(texture: texture)