7
votes

I always thought that the the zPosition of a SKNode would be relative to its parent, but right now I'm experiencing the opposite effect.

I have two parent SKNodes in my scene, which have a zPosition of 1 (node1) and 2 (node2). What I want to achieve is that node2 should ALWAYS be layered ABOVE node1. But unfortunately, the child nodes of node1 (which have a zPosition of 1-50) are all layered above the child nodes of node2 (which currently have no zPosition). Is there any way to solve this (except giving node2 a zPosition of more than 50)? Maybe some kind of boolean Parameter to set all child nodes' zPosition relative to its parent? Any help will be appreciated!

EDIT: To make it more clear, here's the hierarchy of all elements:

  • node1:SKNode (zPosition 1)
    • child1:SKNode (zPosition 1)
    • child2:SKNode (zPosition 2)
    • child3:SKNode (zPosition 3)
    • ...
    • child50:SKNode(zPosition 50)
  • node2:SKNode (zPosition 2)
    • child1:SKLabelNode (no zPosition)
    • child2:SKLabelNode (no zPosition)
    • child3:SKLabelNode (no zPosition)
    • ...
    • child50:SKLabelNode (no zPosition)

EDIT2: Here's a very reduced version of my GameScene class:

import SpriteKit

class GameScene: SKScene {

    let gameNode = SKNode()
    let node1 = SKNode()
    let node2 = SKNode()

    let nodeSize:CGFloat = 50.0
    let spacing:CGFloat = 5.0

    required init(coder aDecoder: NSCoder) {
        fatalError("NSCoder not supported")
    }

    override init(size: CGSize) {
        super.init(size: size)

        self.addChild(gameNode)

        node1.name = "node1"
        node2.name = "node2"

        node1.zPosition = 1
        node2.zPosition = 2

        gameNode.addChild(node1)
        gameNode.addChild(node2)

        // add children to node1
        for i in 1..<10 {
            let child = SKSpriteNode(color: UIColor.redColor(), size: CGSize(width: nodeSize, height: nodeSize))
            child.position = CGPointMake((nodeSize + spacing) * CGFloat(i), 0)
            child.zPosition = CGFloat(i)
            self.node1.addChild(child)
        }

        // add children to node2
        for i in 1..<10 {
            let child = SKLabelNode(fontNamed: "Avenir Black")
            child.position = CGPoint(x: (nodeSize + spacing) * CGFloat(i), y: 0)
            child.text = "label\(i)"
            child.fontSize = 10
            child.fontColor = UIColor.blackColor()
            self.node2.addChild(child)
        }
    }
}

When you run it, you can see that only the first child of node2 (label1) is layered above the first child of node1 (since they have the same zPosition). All others are layered underneath the children of node1.

1
Have you considered adding the label as a child of the sprite? You will need to set the label's position to CGPointZero to make that work.0x141E
Thanks, but my intention is not to set the labels as a child of the spritesbiedert
Why do you want the nodes to be ordered in this way?0x141E
Just to have different layers in my scene to make sure that all of their children are layered by the zPosition of their parent. But the children also need to have different zPositions within their parent, Also, all children have their own SKActions, which should be independent from its parent position, which is why I can't just put the labels inside the sprites and give it a CGPointZero biedert

1 Answers

14
votes

When reading the Apple Documentation regarding this, you can find:

Maintaining the order of a node’s children can be a lot of work. Instead, you can give each node an explicit height in the scene. You do this by setting a node’s zPosition property. The z position is the node’s height relative to its parent node, much as a node’s position property represents its x and y position relative to parent’s position. So you use the z position to place a node above or below the parent’s position.

When you take z positions into account, here is how the node tree is rendered:

  • Each node’s global z position is calculated.
  • Nodes are drawn in order from smallest z value to largest z value.
  • If two nodes share the same z value, ancestors are rendered first, and siblings are rendered in child order.

The point I found - which i didn't know it was like this - is that the children zPosition is calculated summating their parents zPosition, so if node1.zPosition + (node1's)child3.zPosition = 4, and node2.zPosition + (node2's)child3.zPosition = 3, the node1's child will be painted above.

Solution: Set node2.zPosition bigger than (node1's)lastChild.zPosition + node1.zPosition.