Center SKLabelNode in SKSpriteNode - swift

I have a SKSpriteNode with an attached image
menu_bg = SKSpriteNode(imageNamed: "menu_bg")
Additionally I want a SKLabelNode to be added as a child of menu_bg and this SKLabelNode should be centered horizontally and vertically wihtin the menu_bg node.
To do so, I added the menu_bg to the scene
self.addChild(menu_bg)
And I create a new SKLabelNode and add it to the menu_bg and try to place it centered
self.menu_bg.addChild(menuTitleLabel!)
self.menuTitleLabel!.position = CGPoint(x: menu_bg.frame.width/2, y: menu_bg.frame.height/2)
But the Label is not displayed centered.
Any ideas what I am missing?
I also tried to add
self.menuTitleLabel!.horizontalAlignmentMode = SKLabelHorizontalAlignmentMode.Center
but with no effect,...
any ideas?

If you are setting the position, you will need to account for the menuTitleLabel height and width as well.
self.menuTitleLabel!.position = CGPoint(x: menu_bg.frame.width/2 - (menuTitleLabel.frame.width/2), y: menu_bg.frame.height/2 -(menuTitleLabel.frame.height/2))
This should center it.

I followed the hint of #Glideman and when I set the label to 0,0 they were already centered, since the anchor of a SpriteNode is always in it´s center - as I learned now ;-)
Thank you for your help and approach to find a solution :)

Related

SpriteKit - Nodes not adding to SKCameraNode - Swift

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.

Background image in gamescene.swift

What do I need to code in order to have an image (that is already in the assets.xcassets) displayed as the background of the GameScene.swift?
First of all you could call you scene with the scaleMode .resizeFill that modify the SKScene's actual size to exactly match the SKView :
scene.scaleMode = .resizeFill
.resizeFill – The scene is not scaled. It is simply resized so that its fits the view. Because the scene is not scaled, the images will all remain at their original size and aspect ratio. The content will all remain relative to the scene origin (lower left).
By default, a scene’s origin is placed in the lower-left corner of the view. So, a scene is initialized with a height of 1024 and a width of 768, has the origin (0,0) in the lower-left corner, and the (1024,768) coordinate in the upper-right corner. The frame property holds (0,0)-(1024,768).The default value for the anchor point is CGPointZero (so you don't need to change it), which places it at the lower-left corner.
Finally, you can use the code below to add your background image (called of example bg.jpg):
// Set background
let txt = SKTexture(imageNamed: "bg.jpg")
let backgroundNode = SKSpriteNode(texture: txt, size:size)
self.addChild(backgroundNode)
backgroundNode.position = CGPoint(x: self.frame.midX, y: self.frame.midY)
Although this might not be the best way, but it's what I always do, and it works.
Assuming that you have an image that is exactly the same aize as your scene, you can do this:
// please declare bg as a class level variable
bg = SKSpriteNode(imageNamed: "name of your texture")
// the below two lines of code is my preference only. I want the
// background's anchor point to be the bottom left of the screen
// because IMO it's easier to add other sprites as children of the background.
bg.anchorPoint = CGPoint.zero
bg.position = CGPoint(x: self.frame.width / -2, y: self.frame.height / -2)
self.addChild(bg)
Alernatively, just do this in an sks file. It's much easier.
After that, add all your game sprites as children of bg instead of self because it is easier to manage.

Increase Touchable Area of an SKSpriteNode

I know a similar question has been asked before about this topic but here is my problem. I am using the following simple code to touch and SKNode.
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
let touch = touches.first as UITouch!
let location = touch.locationInNode(self)
let node = self.nodeAtPoint(location)
I then remove the touches node with the following:
node.removeFromParent()
Now, my problem is that the image of the node I am touching is small. Therefore it is very hard to accurately register a touch. I do not want to make the image bigger. This wouldn't be a problem but the nature of my game is such that I:
1) Cannot use another invisible SKSpriteNode ontop of my image SKSpriteNode to increase the registered touch area because each image has a unique name so I need that specific node to be touched and removed.
2) I cannot give the invisible SKSpriteNode the same name as the image SKSpriteNode because then only the invisible SKSpriteNode would be removed on touching.
3) I have tried to load a new SKSpriteNode into the original image SKSpriteNode to increase the touchable area, but once again, on touching, only the invisible SKSpriteNode gets removed, not the image SKSpriteNode which I want.
So, how can I increase the touchable area? Is there a way to maybe:
1) Remove all nodes associated with the node that is touched? This would then work if I put an invisible SKSpriteNode inside the original node to increase the touchable area. If they had the same name. But I have already tried "node.removeAllChildren()"......didn't work.
2) Detect a touch and the closest possible image near that touch is the image that the code in TouchesBegan gets use on? This would also work for my situation.
Any other suggestions? Cheers :)
-------------------------------UPDATE---------------------------
The following code below works! If I touch the invisible SKNode, then both the invisible and Original SKNodes disappear. However, for whatever reason, the original SKNode always appears infront of the invisible SKNode. I cannot fix this?
let original = SKSpriteNode(imageNamed: "original")
original.size = CGSize(width: 50, height: 50)
original.zPosition = 0
let invisible = SKSpriteNode(color: UIColor.redColor(), size: CGSizeMake(70, 70))
invisible.position = CGPoint(x: CGRectGetMidX(self.frame), y: CGRectGetMidY(self.frame))
invisible.alpha = 1.0
invisible.zPosition = 1
invisible.name = original.name
invisible.addChild(original)
self.addChild(invisible)
For zPosition order, put this inside GameViewController
//Put this line
skView.ignoresSiblingOrder = true
//before this
skView.presentScene(scene)
In you code you have two nodes:
original
invisible
Who is the parent, who is the child?
According to your question "If I touch the invisible SKNode, then both the invisible and original SKNodes disappear..however, for whatever reason, the original SKNode always appears infront of the invisible SKNode" seems that you want invisible inside original, in other words original should be the parent and invisible should be the child.
But your code says the exact opposite:
invisible.addChild(original)
self.addChild(invisible)
So , we make an example:
Suppose that your original node is green, this how appear your elements follow your code: invisible node (red) do an addChild to the original (green) , and then you add to self the invisible. Invisible is parent, original is child.
Finally, if you touch the red rectangle to remove it, both red and childs (green) will be removed, if you touch the green rectangle to remove it, only the green rectangle disappear.
Hope you can help you to understand what happen to your code.

SKLabelNode Not Showing [SpriteKit]

I created a SKShapeNode called smallScreen and an SKLabelNode with the name screenLabel.
I later attempted to display screenLabel in smallScreen. When I ran the code however, it didn't work. I tried adding screenLabel as a child to self, and that seemed to allow the text to display. Whenever I added screenLabel as a child node to smallScreen, it wouldn't display. Please help, much thanks.
self.smallScreen = (self.childNodeWithName("screen") as? SKShapeNode)!
self.smallScreen.position = CGPoint(x: self.frame.size.width/2, y: self.frame.size.height * 2/3)
screenLabel.text = "Screen"
screenLabel.fontSize = 30
screenLabel.fontColor = UIColor.redColor()
screenLabel.position = CGPoint(x: self.frame.size.width/2, y: self.frame.size.height * 2/3)
screenLabel.hidden = false
self.smallScreen.addChild(screenLabel)
In Sprite-kit by default, a scene’s origin is placed in the lower-left corner of the view. Its default value is CGPointZero and you can’t change it. (source).
A sprite’s (SKSpriteNode) anchor point defaults to (0.5,0.5), which corresponds to the center of the frame (source).
SKShapeNode does not have an anchorPoint.
LearnCocos2D answered on this issue:
When you use an image you may need to align it on its node's position.
There's no other way to do so but through anchorPoint because the
image itself can't be modified (not easily anyway).
When you create a shape you have full control over the alignment of
the shape through CGPath. You can simply translate the path to change
the shape's alignment relative to the node's position.
This is my interpretation, not fact.
So , what happened to your code?
I don't know how you have initialized your shape, I make just an example:
/* Create a Shape Node representing a rect centered at the Node's origin. */
#available(iOS 8.0, *)
public convenience init(rectOfSize size: CGSize)
So we create the shape like this:
self.smallScreen = SKShapeNode.init(rectOfSize: CGSizeMake(200,200))
First, you place your SKShapeNode to the X center of the screen for the X coordinates, and Y = self.frame.size.height * 2/3. In fact, your smallScreen is visible.
Speaking about your label, you have add it to the smallScreen, so screenLabel must respect the alignment of his parent.
In fact you can see your label simply by making this change:
From:
screenLabel.position = CGPoint(x: self.frame.size.width/2, y: self.frame.size.height * 2/3)
To:
screenLabel.position = CGPointZero
and your label is positioned to the center of the smallScreen according to the alignment of his parent.

SpriteKit node not respecting position

I have added a SKNode to my SKView by using this code:
tile.fillColor = SKColor.blueColor()
tile.position = CGPoint(x: 64, y: 64)
self.addChild(tile)
However, after fiddling with window sizes in the MainMenu.xib file, the position of tile becomes inaccurate even when the SKView lines up with the window itself:
How do I fix this?
Modifying the tile's anchor point might make it easier to place. I'm not 100% clear on where precisely you want to place that tile, but if you were trying to get that tile lined up on the bottom edge, and 64 from the left edge of the parent, you could simplify things by moving the anchor point of the tile to its bottom left before placing it. By default, as rakeshbs points out, the anchor point is at the center of the tile.
tile.fillColor = SKColor.blueColor()
tile.anchorPoint = CGPointMake(0, 0)
tile.position = CGPoint(x: 64, y: 0)
self.addChild(tile)
Maybe you're already aware of the ability to modify the anchor point on a SKSpriteNode, if so please disregard; perhaps I'm not fully understanding your issue.