I am setting up a scene with a fixed background (a simple rectangle), an SKEmitterNode, and a backgroundLayer (a SKNode including many SKShapeNodes) : this is the hierarchy of my scene. But, even if I am adding the emitter node as a child of the scene just after the fixed background and just before the background layer, the particles emitted are at the foreground, which is not what I am expecting. indeed, I would like them to be rendered between the fixed background and the background layer, which is not happening.
I am running this app on ios 10. I've tried to add childs in a different order, or to change the target node, but it didn't change anything...
All of the following code comes from 'init(size: CGSize) {}' of a scene class which inherits from SKScene.This is all the scene set up process (when childs are added).
anchorPoint = CGPoint(x: 0, y: 0)
background.position = CGPoint(x: sceneSize.width / 2, y: sceneSize.height / 2)
background.fillColor = UIColor(white: 0.5, alpha: 1)
background.strokeColor = UIColor.lightGray
addChild(background)
setUpParticleEmitter() // it sets up the particle emitter which is an attribute of the class
addChild(backgroundEmitter) // This is the name of the emitter
backgroundEmitter.targetNode = scene
backgroundLayer.position = CGPoint(x: 0, y: 0)
addChild(backgroundLayer)
gameLayer.position = CGPoint(x: -1 * sceneSize.width, y: 0) // another layer for futur nodes
addChild(gameLayer)
I expect the particles to be rendered between 'background' and 'backgroundLayer', but they are rendered at the foreground (=over the backgroundLayer's childs), is it possible to change that ?
You can chose which nodes to be in front and which in back by setting them the zPosition.
first_node.zPosition = 1
second_node.zPosition = 2 // displayed over first node
Related
Completely new to SpriteKit. Currently I have a UIView, and I want to add a sprite node to it (like a small UIImageView, but I want animation for it so using SpriteKit). Therefore I didn't initialize my project to be a game project, as found in almost all of tutorials for SpriteKit. I've found a note here: link and what I have now is sth like:
func initializeImage() {
let imageView = SKView()
imageView.frame = CGRect(x: self.frame.width / 2 - Constants.imageWidth / 2, y: self.frame.height - Constants.imageHeight, width: Constants.imageWidth, height: Constants.imageHeight)
// so place it somewhere in the bottom middle of the whole frame
let sheet = SpriteSheet(texture: ...)
let sprite = SKSpriteNode(texture: sheet.itemFor(column: 0, row: 0))
sprite.position = imageView.center //basically the same position as the imageView.frame's x and y value
let scene = SKScene(size: imageView.frame.size)
scene.backgroundColor = SKColor.clear
scene.addChild(sprite)
imageView.presentScene(scene)
self.frame.addSubview(imageView)
}
The SpriteSheet is similar to this: sprite sheet; it's essentially cutting an image atlas and divide it into smaller images. I tracked the process and this step is indeed giving the smaller image (the var 'sprite'). But if running I only have a black square now (should be the size as defined by Constants). If I set scene.backgroundColor to be white then it's white. May I know how I should proceed from here, as how should I make the sprite showing up?
All of your code looks good except for this:
sprite.position = imageView.center // basically the same position as the imageView.frame's x and y value
That is basically not the position you think it is. The coordinate system in SpriteKit is a) relative to the (SK)scene, not to whatever view the SKView is contained in, and b) flipped vertically relative to the UIKit coordinate system. If you want a sprite centered in the scene, you probably want to set its position based on the scene's size:
sprite.position = CGPoint(x: scene.size.width / 2, y: scene.size.height / 2)
By the way, the external SpriteSheet code might not be needed (and you're more likely to benefit from Apple's optimizations) if you slice up your sprite sheet and put it in an Xcode asset catalog.
Im trying to pin the game pad controller to the bottom left on my camera node but when i add the node as a child of my camera it doesnt show up?
let gameCamera = SKCameraNode()
var joypadBackground : SKSpriteNode = SKSpriteNode(imageNamed: "a")
override func didMove(to view: SKView) {
//Set game camera
self.camera = gameCamera
joypadBackground.position = convert(CGPoint(x: 0, y: 0), to: gameCamera)
joypadBackground.size = CGSize(width: 50, height: 50)
joypadBackground.zPosition = 1000
gameCamera.addChild(joypadBackground)
}
I had a hard time with this same problem the first time I was working with SKCameraNode and creating a heads up display.
Basically you have to remember that there are two parts to the camera. Running its functionality and rendering its children. By setting the scene's camera to gameCamera you've setup the functionality, but your camera isn't in the node tree for rendering. So, if you ever have a camera that needs to render its children don't forget to add it to the scene as a child, then the camera's children will be displayed.
self.camera = gameCamera
self.addChild(gameCamera)
Hope that helps someone avoid a very common error with a very simple solution.
You don't need
convert(CGPoint(x: 0, y: 0), to: gameCamera)
You can just set the CGPoint position to (0,0) and it should be at that point relative to the camera's space.
Not sure if this helps, at all, but what I do is (generally) position a child node AFTER I've added it to its parent. This is mainly a mental reminder, to me, that the child's position is within the coordinate space of the parent. So I'd do something like this:
gameCamera.addChild(joypadBackground)
joypadBackground.position = CGPoint(x: 0, y: 0)
If you're using a mid screen origin in your SKScene, this should be in the middle of the screen.
Bottom left will be a negative x and negative y value, size of which is relative to your frame size.
I am a complete beginner at Swift 3 and programming in general so this will be an incredibly basic question.
I have been following tutorials and am currently positioning a SpriteNode using CGPoint. The tutorial recommends the following to position the Node centrally at the bottom of the screen:
Ground.position = CGPoint(x: self.frame.width / 2, y: 0)
However, that causes it to stick to the top-right of the screen.
When I use the following code:
Ground.position = CGPoint(x: 0 - self.frame.width / 2, y: 0 - self.frame.height / 2)
It positions at the bottom-centre as intended.
I do not understand why this happens as there is very little else done in the tutorial at this point to cause the error.
Set the anchorPoint of the scene to the bottom left corner at the beginning of your didMove(toView: SKView) (or in GameViewController):
scene.anchorPoint = CGPoint(x: 0, y: 0)
Keep in mind that everything you place on the scene is placed based on the anchorPoint. So with this anchorPoint, the origin of your scene is the bottom left corner.
Also note that if you're using .AspectFill as your sceneScaleMode, you don't have to use self.frame and instead set the scene size to 768x1024 (portrait)/ 1024x768 (landscape) then just use number values within the scene size.
Additionally, there are advantages of setting your scenes anchorPoint to the centre:
scene.anchorPoint = CGPoint(x: 0.5, y: 0.5)
This makes it easier to fit the scene into iPad size as well as iPhone, and also simplifies centering nodes.
See this link for more info on making your app universal: iOS Universal Device App with SpriteKit, how to scale nodes for all views?
I want to create my player on top of the background. Somehow this doesn't work. The node counter goes up by one but it isn't visible. I do add the player after I add the background so it should be on top. The code I use to create the player:
var player = SKSpriteNode()
func addPlayer(gameScene: GameScene, xPos: CGFloat, yPos: CGFloat){
player = SKSpriteNode(imageNamed: "player")
player.size = CGSize(width: fieldsWidth, height: fieldsWidth)
player.position = CGPoint(x: xPos, y: yPos)
gameScene.addChild(player)
}
And I access the function from another class like this:
person().addPlayer(self, xPos: fieldsWidth/2, yPos: fieldsWidth/2)
Hopefully you can help me.
If you are sure that you have added node at desired position, which is probably the situation here because node count is incremented, you can set player's and background's zPosition to make player above the background:
var player = SKSpriteNode()
//1. somewhere in your code set background's zPosition to 1 before you add it to the scene
func addPlayer(gameScene: GameScene, xPos: CGFloat, yPos: CGFloat){
player = SKSpriteNode(imageNamed: "player")
//2. Set player's zPosition to be higher than background's zPosition
player.zPosition = 2
player.size = CGSize(width: fieldsWidth, height: fieldsWidth)
player.position = CGPoint(x: xPos, y: yPos)
gameScene.addChild(player)
}
About ignoresSiblingOrder...I would recommend you to leave that to true because it can help a lot when it comes to performance . The only "thing" about this kind of optimization is that you have to explicitly set zPosition for nodes at same zPosition which can overlap, but you don't want to let them overlap in random order (which ignoresSiblingsOrder does when set to true), but rather to overlap in determined order (controlled by you). This is from docs:
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.
So, just set zPosition explicitly and you will be fine.
In the View Controller of your scene, set skView.ignoresSiblingOrder = false.
Here's what I have so far in my didMoveToView() function:
backgroundLayer.zPosition = -1
hudLayer.zPosition = 100
addChild(backgroundLayer)
addChild(hudLayer)
backgroundColor = SKColor.whiteColor()
let healthBar: SKSpriteNode = SKSpriteNode(imageNamed: "Healthbar")
healthBar.position = CGPoint(x: 0, y: 0)
healthBar.anchorPoint = CGPoint(x: 0, y: 1.0)
hudLayer.addChild(healthBar)
My background shows up fine, and I have both a backgroundLayer and a hudLayer. I even made the zposition much higher for the hudLayer to make sure it's in front. As for the positioning, I think I have the anchor point to be at the top-left of the sprite, and tried various ways to position it- it seems to only show up when I use something like:
healthBar.position = CGPoint(x: 0, y: size.width/2)
My question is why? size.width/2 isn't working for when I test on different screen sizes (on an iphone4, the health bar is further down).
Doesn't size take the current size of the screen? I thought using size would make it somewhat 'responsive' but I can't get the behavior to work right. Therefore, I thought maybe the CGPoint coordinate system (0-1.0) would work better, but it's not showing up at all with that.
Thanks for reading, I don't understand why it won't show up :(