1

I have two SKLabelNodes, one which displays the score and another which acts as a shadow behind the score. Every time my player passes through a goal I update the score labels to increment by 1 point by calling the updateScoreLabels() method below.

But for some reason no matter what zPosition I set for each of these SKLabelNodes, the two nodes are drawn in a random order and every time I call the updateScoreLabels() method their order flips randomly. It also doesn't seem to matter what I have .ignoresSiblingOrder set to or make a difference if I add one SKLabelNode as a child of the other. The nodes just ignore zPosition altogether. What am I doing wrong? Here is my code:

This method is called in didMoveToView():

func createScoreLabel() {
    //Configure score label
    scoreLabel = SKLabelNode(fontNamed: "8BIT WONDER Nominal")
    scoreLabel.text = "O"
    scoreLabel.fontSize = 32
    scoreLabel.position = CGPoint(x: -UIScreen.main.bounds.size.width/2 - scoreLabel.frame.size.width/2, y: UIScreen.main.bounds.size.height/2 - scoreLabel.frame.size.height/2 - 60)
    scoreLabel.zPosition = 999

    //Configure shadow
    scoreLabelShadow.attributedText = NSAttributedString(string: "O", attributes: scoreLabelShadowAttributes)
    scoreLabelShadow.position = CGPoint(x: -UIScreen.main.bounds.size.width/2 - scoreLabel.frame.size.width/2, y: UIScreen.main.bounds.size.height/2 - scoreLabel.frame.size.height/2 - 60)
    scoreLabelShadow.zPosition = -9999999999

    //Add labels
    cam.addChild(scoreLabel)
    cam.addChild(scoreLabelShadow)

    //Animate labels
    scoreLabel.run(SKAction.move(to: CGPoint(x: -UIScreen.main.bounds.size.width/2 + scoreLabel.frame.size.width/2 + 30, y: UIScreen.main.bounds.size.height/2 - scoreLabel.frame.size.height/2 - 60), duration: 0.1))
    scoreLabelShadow.run(SKAction.move(to: CGPoint(x: -UIScreen.main.bounds.size.width/2 + scoreLabel.frame.size.width/2 + 30, y: UIScreen.main.bounds.size.height/2 - scoreLabel.frame.size.height/2 - 60), duration: 0.1))
}

and then this is called when I increment the score labels. Whenever this is called the zPositions flip randomly:

func updateScoreLabel() {
    let formattedScore = String(score).replacingOccurrences(of: "0", with: "O")

    scoreLabel.text = String(formattedScore)
    scoreLabelShadow.attributedText = NSAttributedString(string: formattedScore, attributes: scoreLabelShadowAttributes)
}
5AMWE5T
  • 841
  • 1
  • 9
  • 25

2 Answers2

1

As I answered here: I usually create enums to establish zPositions, so I can simply manage the different layers:

enum ZPositions: Int {
    case background
    case foreground
    case player
    case otherNodes
}
  • “case background” is the lower position, it’s equal to the default position of 0;
  • “case foreground” = 1
  • “case player” = 2
  • “case other nodes” = 3

So, when you setup a new item, you can give it the zPosition simply this way:

button.zPosition = CGFloat(ZPosition.otherNodes.rawValue)

(button now has the highest zPosition) Hope it helps...

DaniChi
  • 301
  • 3
  • 12
0

Try to reset zPositions each time you update labels see if that resolves.

func updateScoreLabel() {
    let formattedScore = String(score).replacingOccurrences(of: "0", with: "O")

    scoreLabel.text = String(formattedScore)
    scoreLabelShadow.attributedText = NSAttributedString(string: formattedScore, attributes: scoreLabelShadowAttributes)
    scoreLabel.zPosition = 999
    scoreLabelShadow.zPosition = -9999999999
}

Also, having zPosition range of 999 to -9999999999 is not a good practice which could be the cause of the problem. I highly doubt, you have that many layers in your SKSCene.

Store and re-use your layers' zPositions in a Singleton instance and have a categorical system ie: zPosHUD:CGFloat = 10, zPosPlayer:CGFloat = 3, zPosBackground:CGFloat = -5 etc. This will help you be more organized and eventually less bugs will occur in your application.

Hope this helps.

Vetuka
  • 1,523
  • 1
  • 24
  • 40