Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SpriteKit issue with zPosition

I am encountering an issue with the zPosition of nodes on my SpriteKit scene.

I am building a manager node that enables "layer like" management of nodes zPosition, essentially enabling you to get rid of the manual management of the zPosition property and instead to add nodes with methods like addNodeUnder(node:SKNode) and also to create groups.

Here is a test scene I have made :
We can see a blue node, itself under a green node, itself under a yellow node, itself under a red node.

The problem is that with the operations I have made, the green and the yellow node should be on top of the red node.

I made my own little debugger, displaying the SceneKit "scene graph" in hierarchical order :

Node of type LMManagerNode  has zPosition = 0.0 and has children :
           Node of type LMWarpperNode  has zPosition = 0.0 and has children :
                     Node of type SKSpriteNode ('Red node') has zPosition = 0.0.

           Node of type LMWarpperNode  has zPosition = -100.0 and has children :
                     Node of type SKSpriteNode ('Blue node') has zPosition = 0.0.

           Node of type LMWarpperNode  has zPosition = 100.0 and has children :
                     Node of type LMGroupNode ('Test group') has zPosition = 0.0 and has children :
                               Node of type LMWarpperNode  has zPosition = -150.0 and has children :
                                         Node of type SKSpriteNode ('Yellow node') has zPosition = 0.0.

                               Node of type LMWarpperNode  has zPosition = -200.0 and has children :
                                         Node of type SKSpriteNode ('Green node') has zPosition = 0.0.

As you can see :

  • The red node is contained inside a node that has zPosition = 0
  • The blue node is contained inside a node that has zPosition = -100
  • The yellow and green nodes are contained inside a group node, itself contained inside a node that has zPosition = 100

Since the node that contains the red node has zPosition = 0 and the node that contains the green and yellow nodes has zPosition = 100, shouldn't these two nodes be on top of the red node ?

The ignoresSiblingOrder of my SKView is set to false by the way...

EDIT : That's weird : yellowNode.zPosition = 1000 does make the yellow node go on top of the red node. How can it be possible ?

EDIT #2 Here is the code of my debugging function :

func renderNodeHieararchyForNode(node:SKNode, index:Int) {

    var i = 0
    var beginning = ""
    while i != index {
        beginning += "          "
        i++
        if i == index {
            beginning += " "
        }
    }

    print("\(beginning)Node of type \(node.dynamicType) \(node.name != nil ? "('\(node.name!)')" : "") has zPosition = \(node.zPosition)\(node.children.count > 0 ? " and has children :" : ".")")
    for (i,child) in node.children.enumerate() {
        renderNodeHieararchyForNode(child, index: index+1)

        if i == node.children.count-1 {
            print("")
        }
    }

}

func renderNodeHiearchyForNode(node:SKNode) {
    renderNodeHieararchyForNode(node, index: 0)
}

As you can see, I use only the SpriteKit framework methods to display it, so the output of my debugger is definitely correct.

like image 974
Pop Flamingo Avatar asked Mar 13 '23 16:03

Pop Flamingo


1 Answers

From Apple's documentation,

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.

and

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

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

where

node's global z position = node's z position + node's parent's z position + node's parent's parent's z position + ...

With this formula, the global z positions of your nodes are

red is 0        (0 + 0 + 0)
blue is -100    (0 + -100 + 0)
yellow = -50    (-150 + 0 + 100 + 0)
green = -100    (-200 + 0 + 100 + 0)

From highest to lowest global z position (based on rules 1 and 2), the order in which the nodes appear in the scene is

red
yellow
green / blue

where red appears on top of yellow and yellow is on top of green/blue. Since green and blue have the same global z value, sibling order (rule 3) is used to determine the drawing order. In this case, green's top-level LMWarpperNode node (i.e., its great grandparent) was added to the LMManagerNode node after blue's LMWarpperNode node, so blue is drawn first and green is drawn over blue.

Here's the final (reversed) draw order

red                0
yellow           -50
green           -100
blue            -100 (parent was added to scene before green's great grandparent)
like image 69
Epsilon Avatar answered Mar 29 '23 02:03

Epsilon