zPosition

时间:2016-01-06 17:14:37

标签: swift sprite-kit

我在SpriteKit场景中遇到了节点的zPosition问题。

我正在构建一个管理节点,支持节点zPosition的“层状”管理,实质上使您能够摆脱zPosition属性的手动管理,而是使用addNodeUnder(node:SKNode)等方法添加节点还要创建组。

这是我做过的测试场景:
We can see a blue node, itself under a green node, itself under a yellow node, itself under a red node.

问题在于,通过我所做的操作,绿色和黄色节点应该在红色节点的顶部

我制作了自己的小调试器,按层次顺序显示SceneKit“场景图”:

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.

如你所见:

  • 红色节点包含在具有zPosition = 0
  • 的节点内
  • 蓝色节点包含在具有zPosition = -100
  • 的节点内
  • 黄色和绿色节点包含在一个组节点内,该节点本身包含在具有zPosition = 100
  • 的节点内

由于包含红色节点的节点具有zPosition = 0且包含绿色和黄色节点的节点具有zPosition = 100,因此这两个节点不应该在顶部红色节点?

我的ignoresSiblingOrder的{​​{1}}顺便设置为SKView ...

编辑:这很奇怪:yellowNode.zPosition = 1000确实使黄色节点位于红色节点的顶部。怎么可能?

编辑#2以下是我的调试功能的代码:

false

正如您所看到的,我只使用SpriteKit框架方法来显示它,因此我的调试器输出肯定是正确的。

2 个答案:

答案 0 :(得分:4)

来自Apple的文档,

  

z位置是节点相对于其父节点的高度,就像节点的position属性表示相对于父节点的x和y位置一样。因此,您使用z位置将节点放置在父节点的上方或下方。

  

考虑z位置时,节点树的方式如下   渲染:

     
      
  1. 计算每个节点的全局z位置。
  2.   
  3. 按照从最小z值到最大z值的顺序绘制节点。
  4.   
  5. 如果两个节点共享相同的z值,则首先呈现祖先,并按子顺序呈现兄弟节点。
  6.   

,其中

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

使用此公式,节点的全局z位置为

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

从最高到最低的全局z位置(基于规则1和2),节点在场景中的显示顺序是

red
yellow
green / blue

其中红色显示在黄色顶部,黄色显示在绿色/蓝色顶部。由于绿色和蓝色具有相同的全局z值,因此使用兄弟顺序(规则3)来确定绘制顺序。在这种情况下,绿色的顶级LMWarpperNode节点(即其曾祖父母)被添加到蓝色LMManagerNode节点之后的LMWarpperNode节点,所以蓝色首先绘制,绿色绘制为蓝色。

这是最终(反向)抽奖顺序

red                0
yellow           -50
green           -100
blue            -100 (parent was added to scene before green's great grandparent)

答案 1 :(得分:2)

以下是您现在对代码的期望

 -100: Node
     # 0: Node
        # 0: Blue
   0 : Node
     # 0: Node
        # 0:Red
 100 : Node
     # 0: Node
        # -200:Green
        # -150:Yellow

但真正发生的是这个

 -100: Node
     : Node
     : Blue
     : Green
 -50 : Yellow
   0 : Node
     : Node
     : Red
 100 : Node
     : Node

这是因为zPosition只是从父节点中减去,然后屏幕将1遍传递所有节点。

要解决此问题,您需要创建一个自定义类来覆盖addChild函数并执行一些操作,以便在另一个变量(可能是字典)中跟踪您的zPosition,然后设置子zPosition为零,并使用insertChild(node:, atIndex:)使用此新变量将子项按顺序放置在子数组中以保留您的顺序。然后,如果你更疯狂,你必须跟踪一个孩子何时更改其zPosition,并使用上面的样式在数组中正确设置