SKSpriteNode gets hidden below parent node
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.
How to position child SKSpriteNodes inside their parents
The default anchor point in SpriteKit is (0.5, 0.5), which is the center of a node/sprite. (0, 0) is bottom left corner and (1, 1) is top right corner. Look at this picture.
After choosing a node's anchor point, you can treat it as the origin of a coordinate system whose range is the node's frame size. The position offset is calculated/affected by both the child's anchor point and its parent's anchor point.
For example, a (red) parent node rect
is (100, 100) in size and a (green) child node child
is (50, 50) in size. Set the child position at (-25, 25) in parent's coordinate system will have the following result.
// parent node
let parent = SKSpriteNode(color: UIColor.redColor(), size: CGSizeMake(100.0, 100.0))
parent.position = CGPoint(x:CGRectGetMidX(self.frame), y:CGRectGetMidY(self.frame));
self.addChild(parent)
// child node
let child = SKSpriteNode(color: UIColor.greenColor(), size: CGSizeMake(50.0, 50.0))
child.zPosition = 1
child.position = CGPointMake(-parent.size.width/4, parent.size.height/4) // (-25, 25))
parent.addChild(child)
More experiments of SpriteKit position and anchor point can be found here.
Sprite Kit: can not see existing node's children
You are forgetting that the coordinate system of a node's child is different than that of the parent. Your parent node's "worldNode" position might be at x:500, y:500 and adding a child 20 points on top of the parent is going to x:0 y:20.
You are adding the child by using worldNode coordinates and not parent coordinates.
Child node not keeping same physicsBody when added to parent
I'm not sure if it is a bug in the Scene editor, but adding the physics bodies programmatically yields results as expected.
Some interesting things worth noting are:
the physicsBodies moved with the parent regardless of if they were not Dynamic or not.
I could not get them to overlap each other until I made them all have the same contactTestBitMask
It is difficult to tell in the screen shot but all 3 children kept their physics shapes
If the parent has a physics body and an physics impulse is applied to it, only the parent moves. However setting the position of the parent programmatically moves the parent and child nodes
testObject = SKSpriteNode(texture: nil, color: .greenColor(), size: CGSize(width: 100, height: 100))
testObject.zPosition = Layer.Controls.rawValue
testObject.position = CGPoint(x: self.size.width / 2, y: self.size.height / 2)
// testObject.physicsBody = SKPhysicsBody(circleOfRadius: testObject.width / 2)
// testObject.physicsBody!.dynamic = true
// testObject.physicsBody!.affectedByGravity = false
// testObject.physicsBody!.allowsRotation = true
addChild(testObject)
let testerObject = SKSpriteNode(texture: nil, color: .clearColor(), size: CGSize(width: 100, height: 100))
testerObject.zPosition = Layer.Controls.rawValue
testerObject.position = CGPoint(x:50, y: 50)
testerObject.physicsBody = SKPhysicsBody(circleOfRadius: testerObject.width / 2)
testerObject.physicsBody!.affectedByGravity = false
testerObject.physicsBody!.dynamic = true
testerObject.physicsBody!.allowsRotation = true
testerObject.physicsBody!.collisionBitMask = 0
testerObject.physicsBody!.contactTestBitMask = 0
testObject.addChild(testerObject)
let testerObject2 = SKSpriteNode(texture: nil, color: .clearColor(), size: CGSize(width: 100, height: 100))
testerObject2.zPosition = Layer.Controls.rawValue
testerObject2.position = CGPoint(x:-50, y: -50)
testerObject2.physicsBody = SKPhysicsBody(circleOfRadius: testerObject.width / 2)
testerObject2.physicsBody!.affectedByGravity = false
testerObject2.physicsBody!.dynamic = true
testerObject2.physicsBody!.allowsRotation = true
testerObject2.physicsBody!.collisionBitMask = 0
testerObject2.physicsBody!.contactTestBitMask = 0
testObject.addChild(testerObject2)
let testerObject3 = SKSpriteNode(texture: nil, color: .clearColor(), size: CGSize(width: 100, height: 100))
testerObject3.zPosition = Layer.Controls.rawValue
testerObject3.physicsBody = SKPhysicsBody(circleOfRadius: testerObject.width / 2)
testerObject3.physicsBody!.affectedByGravity = false
testerObject3.physicsBody!.dynamic = true
testerObject3.physicsBody!.allowsRotation = true
testerObject3.physicsBody!.collisionBitMask = 0
testerObject3.physicsBody!.contactTestBitMask = 0
testObject.addChild(testerObject3)
Unable to hide/unhide the SKSpriteNode
If I catch what you mean, you want to show startSprite
when a title is pressed (whose name
is normal
, and hide startSprite
when other place except the title is pressed. I suggest you give every node a name
before adding it to the scene. In this way, it is easier to tell which thing you've touched. Hope this will help:
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
for touch in touches {
let location = touch.locationInNode(self)
let touchNode = self.nodeAtPoint(location)
if touchNode.name == "normal" {
startSprite.hidden = false
} else {
startSprite.hidden = true
}
}
}
Swift SKSpriteNode will disappear but is still clickable
It is because your check for which button is pressed does not take into account whether the button is visible.
Even if a node has been removed from its parent, it still has a position
and size
. Those two properties are used by containsPoint:
to determine if a point is in a node
The easiest way to fix it would be to just check if the button has a parent node before checking to see if the button contains the point.
if InventoryButton.parrent != nil && InventoryButton.containsPoint(touch.locationInNode(self)) {
print("Show Inventory")
ShowInventory()
}
Related Topics
How to Replace the Values of Labels in iOS-Charts
Integer Literal Overflows When Stored into 'Int'
Swift Change the Tableviewcell Border Color According to Data
Catch Any Error, Specially Unexpectedly Found Nil in Swift
Swiftui Overlay Blocking List Scroll Events
Avplayer Seektotime Not Working Properly
Firebasecore Lexical or Preprocessor Issue
Sktexture Nearest Filtering Mode Doesn't Work (Making Pixel Art)
How to Implement a 'Next' Property to a Caseiterable Enum in Swift
Appdelegate Segue Alternative Pass Data
How to Get Notification Authorization Status in Swift 3
How to Split a String into a [String] and Not [Substring]
Why Are Properties of an Immutable Object Mutable in Swift
Swift - Getting Only Alphanumeric Characters from String
Nsinvocationoperation' Is Unavailable in Xcode 6.1
Swiftui: How to Switch to a New Navigation Stack with Navigationviews