6
votes

Using Swift and SpriteKit, I have a problem with SKSpriteNode not showing when being added as a child to another SKSpriteNode. In contrast, a SKLabelNode put in exactly the same place does show up.

// does not show up, expected a white square
override func renderBody(parentNode: SKNode, position: CGPoint) {
    let node = SKSpriteNode(color: UIColor.whiteColor(), size: CGSize(width: 48, height: 48))
    node.position = position
    parentNode.addChild(node)
}

// does show up as white text in the correct position
override func renderBody(parentNode: SKNode, position: CGPoint) {
    let node = SKLabelNode(text: "hello")
    node.position = position
    parentNode.addChild(node)
}

'parentNode' and 'position' is the same in both cases.

'parentNode' is a larger SKSpriteNode, created with a texture in dark colors, covering the screen as a background.

'position' is CGPoint(x: 50, y: 50).

It looks like that the rectangle sprite gets below the background, while the label sprite gets on top. I experimented by removing the background and adding the rectangle sprite directly to the scene node, and then it does show up.

Does anybody have an idea of what can be wrong?

Edit: Setting the zPosition manually solves the problem. However, I still think there's something which is wrong somewhere. You shouldn't need to set it manually on a child node in order to avoid having its parent node hiding the child. I never had to do this in Xcode 5. And why is there a difference between a labelnode and a sprite node?

Here's an example which hopefully illustrates it better. Create a default SpriteKit, Swift, Iphone project in Xcode 6. Paste the code below into the for-loop in touchesBegan. Remove the "Hello World" label created in didMoveToView. Run it and click somewhere in the middle of the screen.

let location = touch.locationInNode(self)

// LabelNode without manually setting zposition
// visible
let backGround1 = SKSpriteNode(imageNamed:"Spaceship")
backGround1.position = CGPoint(x: location.x, y: location.y + 250)
backGround1.xScale = 0.5
backGround1.yScale = 0.5
self.addChild(backGround1)
let labelNode = SKLabelNode(fontNamed: "ChalkDuster")
labelNode.text = "I am on top"
labelNode.fontSize = 48
labelNode.fontColor = UIColor.yellowColor()
backGround1.addChild(labelNode)

// SpriteNode without manually setting zposition
// hidden under its parent node
let backGround2 = SKSpriteNode(imageNamed:"Spaceship")
backGround2.position = location
backGround2.xScale = 0.5
backGround2.yScale = 0.5
self.addChild(backGround2)
let spriteNode2 = SKSpriteNode(color: UIColor.yellowColor(), size: CGSize(width: 100, height: 100))
backGround2.addChild(spriteNode2)

// SpriteNode with zposition manually set
// visible
let backGround3 = SKSpriteNode(imageNamed:"Spaceship")
backGround3.position = CGPoint(x: location.x, y: location.y - 250)
backGround3.xScale = 0.5
backGround3.yScale = 0.5
self.addChild(backGround3)
let spriteNode3 = SKSpriteNode(color: UIColor.yellowColor(), size: CGSize(width: 100, height: 100))
spriteNode3.zPosition = 0.001
backGround3.addChild(spriteNode3)
1
The zPosition property controls the order in which nodes are drawn. The node with the highest value will be on top. The default value is 0.0x141E
Thanks for the answer! Yes, setting the zPosition to something positive did solve the problem. But I'm not quite satisfied with this solution. Please see the explanation in my editing of the question. I think adding a child with zPosition = 0 should automatically place it on top of its parent.uaknight

1 Answers

11
votes

What you're looking for is the ignoresSiblingOrder property on SKView:

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

The default Xcode 6.x (and maybe 5, I haven't checked) SpriteKit template sets that to true when setting up the SKView in the view controller. With it set to true, the order that you add nodes to the scene does not affect their z-position. If you set it to false, they'll be layered in the order you add them to the scene (or parent node).

That being said, SpritKit can do some optimizations when ignoresSiblingOrder is true (which is why that's the default in the template), so it's probably best to keep it that way if at all possible. In that case, you'll have to manually set the zPosition property of each node though.