Frame of SKShapeNode is offset - swift

I am trying to add a physicsBody to an SKShapeNode that is a rectangle. I built my PhysicsBody using fromEdgesWithLoop using the Node's frame as the CGRect to build it.
Using the debug option to show PhysicsBody, I see that it is actually not centered on my Sprite.
I searched the web to find that I should use this:
scene.scaleMode = .ResizeFill
Sadly, I tried all scaleModes and there are no differences.
I also verified my GameScene's size and it fits the iPad2 screen (my target), 1024x720.
The SKShapeNode is a child of the Scene.
I tried to set the position of my node in the center of the Scene before adding a PhysicsBody with its frame, but this changed nothing. The node was already in the center of the scene.
myShape.position = CGPointMake(CGRectGetMidX(self.frame), CGRectGetMidY(self.frame))
myShape.physicsBody = SKPhysicsBody(edgeLoopFromRect: myShape.frame)

The position of an Edge Loop is relative to the node it's attached to. In general, for an edgeLoopFromRect, the position is given by
edge_loop_position = node.position + rect.frame.origin
In this case, your physics body is offset by the position of myShape. One way to fix this issue is to attach the edge loop to the scene instead of the shape node:
self.physicsBody = SKPhysicsBody(edgeLoopFromRect: myShape.frame )
Alternatively, you can subtract the node's position from the frame's position with
let rect = CGRect(origin:CGPoint(x:myShape.frame.origin.x-myShape.position.x, y:myShape.frame.origin.y-myShape.position.y), size:myShape.frame.size)
myShape.physicsBody = SKPhysicsBody(edgeLoopFromRect:rect)

Related

SpriteKit 'pinned' property allows y-axis change in position

I have a SpriteKit game in which balls bounce around, interacting with other objects.
One of those other objects is a spinner that should rotate around its center, but NOT change its x/y position. It should be stationary except for the rotation.
According to Apple's documentation, node.physicsBody.pinned = true should do exactly what I want, making it so that:
"the node’s position is fixed relative to its parent. The node’s position cannot be changed by actions or physics forces. The node can freely rotate around its position in response to collisions or other forces."
However, that's not what's happening. What's happening is that the spinner's y-axis position changes when a ball hits it squarely -- briefly moving down and then popping back into the correct position.
My code for the spinner (please assume all variables are defined):
for i in 0..<spinners.count {
let spinnerNode = SKSpriteNode(texture: texture)
spinnerNode.position = CGPoint(x: spinners[i].minX, y: spinners[i].minY)
spinnerNode.size = CGSize(width: spinners[i].width, height: spinners[i].height)
spinnerNode.physicsBody = SKPhysicsBody(texture: spinnerNode.texture!, size: CGSize(width: spinners[i].width, height: spinners[i].height))
spinnerNode.physicsBody?.isDynamic = true
spinnerNode.physicsBody?.affectedByGravity = false
spinnerNode.physicsBody?.pinned = true
addChild(spinnerNode)
}
Why on earth is my spinner node moving vertically when a ball collides with it? Why isn't .pinned working as advertised?
Thank you for your help!
I solved the problem by setting the spinner node's mass to a value slightly greater than that of the ball nodes.
node.physicsBody?.mass = 6.0

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.

Can not use CGPoint to set the position in Swift with Sprite Kit

I don't seem to be able to set the position of my node in sprite kit using swift:
let sprite = SKSpriteNode(imageNamed:"Spaceship")
let point: CGPoint = CGPoint(x:10,y:10)
sprite.position = point
self.addChild(sprite)
It works when I do:
sprite.position = CGPoint(x:CGRectGetMidX(self.frame), y:CGRectGetMidY(self.frame));
Any ideas?
I think you problem is, that you just don't see the node. It gets created, but at a point where you don't see it. To change that, open your GameViewController file and add the following line before skView.presentScene(scene):
scene.size = skView.bounds.size
That code will make sure that the size of your scene is the same size as the size of your screen. So now you should be able to see the node.

SKSpriteNode Overlay not been showed

I'm trying to make a overlay in my SpriteKit game.
let overlay = SKSpriteNode(color: UIColor.blackColor(), size: self.size)
overlay.alpha = 0.3
self.addChild(overlay)
The Overlay is not been shown on the screen, what is wrong?
You can set the zPosition to a higher value to ensure it is drawn above sprites with a lower zPosition value.
For overlays, an arbitrary high value can be used to ensure it is drawn above all other sprites.
node.zPosition = 100;
You can read more about zPosition here.