Swift 3 (SpriteKit): Aligning SKPhysicsBody to SKShapeNode - swift

I am creating SKShapeNodes in my program using this:
let points = [CGPoint(x: x, y: y), CGPoint(x: x2, y: y2)]
let line = SKShapeNode(points: &points, count: points.count)
The problem that I am having is that whenever I add a physicsBody to the line, the physicsBody is not aligned with the line. I realise that the issue is because the line's position is always CGPoint(x: 0, y: 0) so the physicsBody is always in the centre of the screen regardless of where the line is. Here is my code for creating the physicsBody:
line.physicsBody = SKPhysicsBody(rectangleOf: (line.frame.size))
If anyone knows how to align the physicsBody to the line, then please reply with your solution. Thanks!

If you want to make a physics body from one point to the other, you may use something like this:
class GameScene:SKScene {
override func didMove(to view: SKView) {
var points = [CGPoint(x: 22, y: 22), CGPoint(x: 155, y: 155)]
let line = SKShapeNode(points: &points, count: points.count)
print(line.frame.size)
line.physicsBody = SKPhysicsBody(edgeFrom: points[0], to: points[1])
addChild(line)
}
}
This will create an edge based physics body using two points. An edge physics body is static by default so keep that in mind. To register a contact (or make a collision with this body) the other body has to be dynamic.
If you want to have this body dynamic, then look for volume based initializers.

Related

SpriteKit CGPath and SpriteMovement

func zombieAI() {
let zombieGreen = SKSpriteNode(imageNamed: "Zombie")
zombieGreen.setScale(0.3)
zombieGreen.zPosition = 3
zombieGreen.physicsBody?.affectedByGravity = false //change this later
zombieGreen.position = CGPoint(x: 200, y: 200)
self.addChild(zombieGreen)
let goToTurret = CGMutablePath()
goToTurret.move(to: CGPoint(x: 0, y: 0))
zombieGreen.run(SKAction.follow(goToTurret, speed: 1.0))
}
I am still learning about CGPaths and my objective of this code was to make the zombie move to the point 0,0. Currently the zombie spawns and just sits where it spawned. I didn't want to use moveTo, which I am more comfortable with, because the zombie may be obstructed by something, so I want the zombie to move at a speed rather than getting to the point in a certain amount of time. Any suggestions on how to use the CGPath correctly or what I could change to achieve my goal? I am very new to this so please respectfully judge my code :)
Try this (not tested):
Replace this line
goToTurret.move(to: CGPoint(x: 0, y: 0))
with
goToTurret.move(to: zombieGreen.position)
goToTurret.addLine(to: CGPoint(x: 0, y: 0))
So you start the path off with the zombie's current position, then add a line from that position to the zombie's intended position.
Hope this helps!

Swift 3 (SpriteKit): SKShapeNode not moving when its image is changed

I have come across an issue with SKShapeNodes that I'm struggling to understand. To help explain and show my problem, I have created a test program. At the start I create a line like this:
var points = [CGPoint(x: -372, y: 0), CGPoint(x: 372, y: 0)]
var Line = SKShapeNode(points: &points, count: points.count)
addChild(Line)
At this point, I am able to change the position of the node, and it prints the position I expect it to be:
Line.position.y = Line.position.y - 50
print("LINEPOS =", Line.position)
It prints:
LINEPOS = (0.0, -50.0)
This makes sense because the SKShapeNode's original position is always (0, 0). However, the next part of the program doesn't work in the same way. I make the new points equal the coordinates of where the Line is now on the screen, and let the Line equal them like this:
points = [CGPoint(x: -372, y: -50), CGPoint(x: 372, y: -50)]
Line = SKShapeNode(points: &points, count: points.count)
Then I change the position of the Line again (this time I moved it down by 200 so the change in position is more noticeable) like this:
Line.position.y = Line.position.y - 200
print("LINEPOS =", Line.position)
It prints:
LINEPOS = (0.0, -200.0)
Even though it prints the position correctly, it is clear that the Line hasn't moved at all on the screen. It is still at the same position as it was when I let the line equal the new points. This means that after letting the SKShapeNode equal a new set of points, it no longer moves on the screen but in the code it says it does.
How can I fix this? If anyone knows please help because I'm really confused.
Try this code:
import SpriteKit
class GameScene:SKScene {
override func didMove(to view: SKView) {
var points = [CGPoint(x: -372, y: 0), CGPoint(x: 372, y: 0)]
var Line = SKShapeNode(points: &points, count: points.count)
addChild(Line)
Line.position.y = Line.position.y - 50
print("LINEPOS =", Line.position)
points = [CGPoint(x: -372, y: -50), CGPoint(x: 372, y: -50)]
Line.removeFromParent()
Line = SKShapeNode(points: &points, count: points.count)
addChild(Line)
Line.position.y = Line.position.y - 200
print("LINEPOS =", Line.position)
}
}
From your code, when you for the second time do something like Line = SKShapeNode = ... the new shape is created, which doesn't have a parent yet. It is not in a node tree. What you are seeing is the old shape, which is not removed from a parent. So, remove that one, and add a new one... Or, don't create a new shape every time, and just change its position.
Also, this can be a bit confusing. Even if you remove the line which says:
Line.removeFromParent()
the code will compile (but you will see two lines).
So, even though you are working on a same variable and a fact that a node can have only one parent, the code still compiles if you don't remove the Line from parent, before you make another addChild(Line) call. How is that possible?
Well, that works because of this:
You create a Line which is a reference to a SKShapeNode which is added to a parent right after its creation. Now, because it is added to a tree, there is another reference pointing to it, because it is a part of a scene's children array.
Then you instantiate a Line variable again, so now it shows on a different SKShapeNode in memory (but the old SKShapeNode is still in a tree). This new SKShapeNode is not added to a tree, and its parent proprety is a nil. Because of this, you can add it again to a tree, without having compiler yelling at you.
EDIT:
To respond to your comments about how to change a path of an SKShapeNode, you could do something like this:
let path = CGMutablePath()
points = [CGPoint(x: -372, y: -250), CGPoint(x: 372, y: -250)]
path.move(to: CGPoint(x: points[0].x, y: points[0].y))
path.addLine(to: CGPoint(x: points[1].x, y: points[1].y))
Line.path = path
just check this once
import SpriteKit
var Line:SKShapeNode!
class GameScene: SKScene {
override func didMoveToView(view: SKView) {
/* Setup your scene here */
var points = [CGPoint(x: -372, y: 0), CGPoint(x: 372, y: 0)]
Line = SKShapeNode(points: &points, count: points.count)
addChild(Line)
}
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
/* Called when a touch begins */
Line.position.y = Line.position.y + 200
}
override func update(currentTime: CFTimeInterval) {
/* Called before each frame is rendered */
}
}

2 bezier path to skspritenode

I would like to create SKSpriteNode from 2 independent bezier paths.
It is similar like road borders. Those paths don't cross but I would like to get 1 SpriteNode as a border of player movement.
The reason is that I want to get equal distance between them. I think that it will be easier for me if I make 1 SkSpriteNode from 2 paths.
I need SKSpriteNode to get contact when player touches that "border"
How to do that?
Thank you
Add an SKSpriteNode:
let container = SKSpriteNode.init(color: UIColor.redColor(), size: CGSizeMake(800, 400))
container.position=CGPointMake(300, 300)
self.addChild(container)
Create an array of CGPoint's. I used just a triangle you can use whatever you want:
let firstPathArray:[CGPoint]=[CGPoint(x: 0, y: 0),CGPoint(x: 100, y: 0),CGPoint(x: 50, y: 100)]
Add path to container:
addbezierPathToContainer(container,pathArray: firstPathArray)
Add path:
func addbezierPathToContainer(container:SKSpriteNode,pathArray:[CGPoint]) -> Void {
let newpath = UIBezierPath()
var startpoint:Bool=false;
for path in pathArray {
if(!startpoint)
{
newpath.moveToPoint(CGPoint(x: path.x, y: path.y))
startpoint=true;
}
else
{
newpath.addLineToPoint(CGPoint(x: path.x, y: path.y))
newpath.addLineToPoint(CGPoint(x: path.x, y: path.y))
}
}
//close path
newpath.closePath()
UIColor.blackColor().setStroke()
newpath.stroke()
let pathNode = SKShapeNode(path: newpath.CGPath)
container.addChild(pathNode);
}

Draw a hole in a rectangle with SpriteKit?

How to draw a hole in a rectangle?
I want to draw a rectangle which has a empty hole inside it and the background can be show.
I am using SKShapeNode to create a rectangle, but I have no idea how to make a hole (circle) inside it.
This is what I run your code, but my circle is not empty, the circle is black, I want it to be empty.
Is there any mistake I didn't mention?
Here's the code.
import SpriteKit
class GameScene: SKScene {
override func didMove(to view: SKView) {
let effect = SKEffectNode()
addChild(effect)
let rect = SKShapeNode(rect: CGRect(x: 0, y: 0, width: 400, height: 200))
rect.fillColor = .green
effect.addChild(rect)
let hole = SKShapeNode(circleOfRadius: 40)
hole.position = CGPoint(x: 200, y: 100)
hole.fillColor = .white
hole.blendMode = .subtract
rect.addChild(hole)
}
}
As you can see I create an SKEffectNode. Then I add to it the rectangle. Finally I add the hole to the rectangle.

Position of a Node after addChild

I have an SKSpriteNode like a light gray square in the view, and I want to put a label inside it... I do this way:
let puntosCubo = SKSpriteNode(color: SKColor.lightGrayColor(), size: CGSize(width: gameoverTitle.frame.width, height: gameoverTitle.frame.height*4))
puntosCubo.position = CGPoint(x: CGRectGetMinX(self.frame)-100, y:y2)
I put a SKLabelNode inside puntosCubo this way:
let puntosCuboTitle1 = SKLabelNode(fontNamed: "Apple SD Gothic Neo")
puntosCuboTitle1.fontColor = SKColor.blackColor()
puntosCuboTitle1.fontSize = 20
puntosCuboTitle1.text = "Score"
puntosCubo.addChild(puntosCuboTitle1)
puntosCuboTitle1.position = CGPoint(x: 0, y: puntosCubo.position.y)
But the result is that the position of the SKLabelNode is not inside puntosCubo. I think i am using the position of puntosCubo on a wrong way...
Any ideas/help. Thanks.
Because of
puntosCubo.addChild(puntosCuboTitle1)
the position of the label puntosCuboTitle1 is relative to the postion of its parent (puntosCubo)
puntosCuboTitle1.position = CGPoint(x: 0, y: 0)
makes the position of the puntosCuboTitle1 in the middle of its parent puntosCubo