I personally think this is really really weird.
I was just developing a game using SpriteKit. I created a subclass of SKSpriteNode
in order to create a sprite that shows how much time is left in the game, the score, etc. I called it GameBanner
.
I am now trying to put an SKLabelNode
in the top left corner of banner. I don't know the exact position of it so I wrote this:
timerTitle.position = //CGPointMake(CGRectGetMinX(self.frame) +
timerTitle.frame.width / 2 + 20, CGRectGetMaxY(self.frame) -
self.frame.height / 2 - 20)
// timerTitle is the label node that shows "Time Left"
But I can only see the banner's background image on the screen, not "Time Left". I think this is because somehow I set the position of timerTitle
to be outside of the banner.
Then I thought, well, this is to much trouble for me to figure where it should be, let's "trial and error" this!
I first tried with (0, 0). It puts the label right in the center. Then I tried these:
I hope you can understand my problem with screenshots:
This is when I first set the position to (-160, 20):
Then I changed it to (-160, 0), it shows up:
After that, I changed it back to (-160, 20) and it magically works!
Here is the GameBanner
class:
class GameBanner: SKSpriteNode {
let timerTitle = SKLabelNode(text: "Time Left:")
let timerLabel = SKLabelNode(text: "60")
let collectedBlocksLabel = SKLabelNode(text: "Collected Blocks")
let scoreLabel = SKLabelNode(text: "Score:")
override init(texture: SKTexture?, color: UIColor, size: CGSize) {
super.init(texture: texture, color: color, size: size)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
//Call this initializer with Position: (302.08, 860.78), Size: (604.16, 100.0) to reproduce
convenience init(position: CGPoint, size: CGSize) {
self.init(texture: SKTexture(imageNamed: "banner"), color: UIColor.clearColor(), size: size)
self.position = position
configureLabels(timerTitle, timerLabel, collectedBlocksLabel, scoreLabel)
// This is the part that doesn't work as I have said above
timerTitle.position = CGPointMake(-160, 20)
addChild(timerTitle)
//addChild(timerLabel)
//addChild(collectedBlocksLabel)
// addChild(scoreLabel)
zPosition = 10000
}
private func configureLabels(labels: SKLabelNode...) {
for label in labels {
label.fontColor = UIColor.whiteColor()
label.fontName = "Chalkduster"
label.fontSize = 25
}
}
}
And this is the background image of the banner. Maybe this matters:
I believe that your issue is related to ignoresSiblingOrder property.
Currently, you have something like this :
parent (which is GameBanner) has zPosition
set to 10000.
label (timerTitle) is added to the parent, and has default zPosition set to 0.0, which means, the rendering (global) zPosition will be 10000 + 0 = 10000. Means, it will be rendered sometimes before (below), and sometimes after (above) its parent.
Try to set zPosition of a label explicitly, to place it above its parent:
convenience init(position: CGPoint, size: CGSize) {
//...
timerTitle.zPosition = 1
//...
zPosition = 10000
}
Now, the global rendering zPositiot will be 10000+1 = 10001, means, that label will be always on top of the banner image.
About ignoresSiblingOrder
property:
The default value is NO, which means that when multiple nodes share the same z position, those nodes are sorted and rendered in a deterministic order. Parents are rendered before their children, and siblings are rendered in array order. When this property is set to YES, the position of the nodes in the tree is ignored when determining the rendering order. The rendering order of nodes at the same z position is arbitrary and may change every time a new frame is rendered. When sibling and parent order is ignored, SpriteKit applies additional optimizations to improve rendering performance. If you need nodes to be rendered in a specific and deterministic order, you must set the z position of those nodes.
More about how node tree is rendered: