0
votes

I have a very weird situation where an SKShapeNode created from a polygon is not showing up when it is added to an SKSpriteNode, but working fine on the base SKScene. (Update - it is solved, see end of question)

As part of the debugging, I attached another SKSpriteNode to the SKShapeNode, to show another image on top.

That second image always appears.

So the working hierarchy is:

  • SKScene
    • SKShapeNode - blue shape
      • SKSpriteNode - Ant picture

Whitespace cropped on this first picture - the Ant is in the same location in both.

SKShapeNode on the SKScene

The non-working hierarchy is:

  • SKScene
    • SKSpriteNode - foot picture
      • SKShapeNode - blue shape (not drawn but its attached Ant is)
        • SKSpriteNode - Ant picture

Image with SKSHapeNode as root - no drawing

Here is hopefully enough of the code to help someone work out what's happening. Note that:

  1. It is not a side-effect of using the points array to construct the drawing - the same thing happens if I create a simple rect shape using either the init(rect:) or init(rectOf:)
  2. It happens on both device and simulator.

Update after scaling to debug, as suggested in comments

Scene background set to red to make it clear.

Scaled scene x 2 to show relative positions

Thanks for any suggestions, I'm at my wits-end here.

the code to attach the drawing and ant pic to a node

  override func applyTo(node:SKNode) -> Bool {
    var pointsVec = renders[0].rescaledPoints().map{ tp in tp.loc }
    let numPointsNow = pointsVec.count
    if numPointsNow==0 {
        return false
    }
    let draw = SKShapeNode(points: &pointsVec, count: numPointsNow)
    draw.lineWidth = 1
    draw.fillColor = fillColor
    draw.strokeColor = fillColor
    draw.position = CGPoint(x: 0, y: 0)
    node.addChild(draw)

    let antNode = SKSpriteNode(imageNamed: "Ant05_150px.png")
    antNode.position = CGPoint(x:0.0, y:0.0)  // for anchor 0,0
    antNode.size = CGSize(width: node.frame.width, height: node.frame.height)
    antNode.anchorPoint = CGPoint(x: 0.0,y: 0.0) 
    draw.addChild(antNode)
    return true
  }

factory function making the SKSpriteNode used for the foot

  override func makeBackgroundNode(_ within:CGSize) -> SKNode? {
    let bgNode = SKSpriteNode(imageNamed: imageName)
    bgNode.size = within
    bgNode.position = CGPoint(x:0.0, y:0.0)  // for anchor 0,0
    bgNode.anchorPoint = CGPoint(x: 0.0,y: 0.0)
    return bgNode
  }

scene factory using the makeBackground

  func makeSKScene(_ within:CGSize) -> SKScene? {
    let scene = tgSKSceneWithTouch(size: within)
    playingBounds = within
    var rootNode : SKNode = scene
    if let bg = currentScene?.background {
      if let bgNode = bg.makeBackgroundNode(within) {
        scene.addChild(bgNode)  
        rootNode = bgNode
      }
...
      currentScene?.applyTo(sourceOfTouches:scene, nodeToAttachChildrenTo:rootNode)
      // iterates down through non-SpriteKit logic to invoke the applyTo
    }

The Answer

Explicitly setting zPosition in applyTo fixes it!

    draw.zPosition = node.zPosition + 1
    node.addChild(draw)

enter image description here

This seems in direct contradiction to the docs

If multiple nodes share the same z-position, those nodes are sorted so that parent nodes are drawn before their children, and siblings are rendered in the order that they appear in their parent’s children array.

Leading me to the conclusion that either the default zPosition for a shape node is different or this mechanism is not applying here for some other reason! (Maybe because of change of node type?)

1
where does your applyTo get called?Knight0fDragon
my guess right now is that your shape does exist, but the points are not relative to the SKSpriteNode, but are instead absolute to the scene, which is throwing it off. To test my theory, in your SKS file, add a multiple of 10 to the width and the height. This will make everything 10 times smaller as the scale mode will kick in, but you should see your blue foot somewhere in the distance.Knight0fDragon
Thanks @Knight0fDragon that has given me a clue! With the scene scaled by 10, if I position the foot node at 0,0 it appears (tiny) in the bottom-left of the screen, no sign of the blue overlay. If I then let the foot anchor be the default 0.5,0.5 and position it in the calculated middle of the giant scene, the blue overlay DOES appear - up and to the right of the foot picture and partly BEHIND the foot picture. I'm playing with a few scaling things to see if I can get it closer.Andy Dent
Wait you see it going behind the foot? Then you have an issue with zposition as well you need to worry aboutKnight0fDragon
I'm very puzzled by the drawing being apparently behind - I thought zPosition was only for SIBLINGS. Have confirmed in debugger that the node the addChild(draw) is being called on is the sprite with foot picture. There are no siblings here - all nested childrenAndy Dent

1 Answers

0
votes

I decided to post my own answer because it's two-part.

As noted in this answer the core problem is the terribly-named ignoresSiblingOrder property of SKView.

It is not just about ignoring sibling order - it also is about ignoring parent-child order.

A Boolean value that indicates whether parent-child and sibling relationships affect the rendering order of nodes in the scene.

So you can either set ignoresSiblingOrder false or you can explicitly set the zPosition even when you are adding child nodes.

Supposition people may think things are working if their order appears to work properly for parent-child. My suspicion is that mixing node types will cause apparently random failures in this theory.

I did further testing with ignoresSiblingOrder=false to confirm it is a factor for me.