SpriteKit CGPath and SpriteMovement - sprite-kit

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!

Related

How can I make an SKPhysicsBody for this image using CGPath?

I am trying to make an SKPhysics body for this SKSpriteNode using a CGPath polygon.
The problem is that when I check for a collision between this node and the player node, the didBeginContact method is executed even though they did not touch each other. I believe their is something wrong with the coordinates but I cannot see the polygon lines, which makes it difficult for me too see the accuracy of the lines.
Here is the code that I am using:
let triangle = SKSpriteNode(imageNamed: "Triangle_ZigZag")
let trianglePath = CGMutablePath()
trianglePath.addLines(between: [CGPoint(x: triangle.size.width,
y: triangle.size.height),
CGPoint(x: triangle.size.width,
y: - triangle.size.height),
CGPoint(x: -triangle.size.width,
y: triangle.size.height / 2)])
trianglePath.closeSubpath()
triangle.physicsBody = SKPhysicsBody(polygonFrom: trianglePath)
Can someone please help me figure out what am I doing wrong ?
Thank You
FYI physics lines are green, so a green sprite probably isn't the best choice you can't see the lines very well.
your sprite has a centre anchorPoint or an anchorPoint of (0, 0) by default. Therefore your physics points need to take that into account. top right corner would be half the width from centre and half the height from centre etc. You have full width from centre and full height from centre, that is the issue.
trianglePath.addLines(between: [CGPoint(x: triangle.size.width / 2, y: triangle.size.height / 2), CGPoint(x: triangle.size.width / 2, y: -triangle.size.height / 2), CGPoint(x: -triangle.size.width / 2, y: 0)])

How to move SKSpriteNode in a curve without rotating the sprite in Swift

I'm trying to move a sprite with a curve.
I got this code:
let path = UIBezierPath()
path.move(to: CGPoint.zero)
path.addQuadCurve(to: CGPoint(x: ball.position.x+200, y: ball.position.y+50), controlPoint: CGPoint(x: ball.position.x+100, y: ball.position.y+200))
ball.run(SKAction.follow(path.cgPath, speed: 1.0))
I have few questions:
1 - why my sprite is rotating while moving, and if I can control this rotation?
2 - any idea why the ball is moving only small part of the way and very slow and not a smooth moving (10-20 seconds)?
Does anyone have any idea how this code works?
All the answers I found were related to older Swift version that had different method.
At last I've found the solution :)
func beizerSprite()
{
// create a bezier path that defines our curve
let path = UIBezierPath()
path.move(to: CGPoint(x: 16,y: 239))
path.addCurve(to:CGPoint(x: 301, y: 239),
controlPoint1: CGPoint(x: 136, y: 373),
controlPoint2: CGPoint(x: 178, y: 110))
// use the beizer path in an action
_playButton.run(SKAction.follow(path.cgPath,
asOffset: false,
orientToPath: true,
speed: 50.0))
}
This move the SKSprite in a curve along the screen.

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 */
}
}

Swift 3 (SpriteKit): Aligning SKPhysicsBody to SKShapeNode

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.

How to make a spritekit node change from one image to another

I have an SKSpriteNode image with the code:
let Drake1 = SKSpriteNode(imageNamed: "Drake1")
Drake1.position = CGPoint(x:self.frame.size.width/3, y:self.frame.size.height - 230)
Drake1.zPosition = 2
addChild(Drake1)
//drake movement
let moveRight = SKAction.moveByX(frame.size.width/2.8, y: 0, duration: 2)
let moveLeft = SKAction.moveByX(-frame.size.width/2.8, y: 0, duration: 2)
let moveBackAndForth = SKAction.repeatActionForever(SKAction.sequence([moveRight, moveLeft]))
Drake1.runAction(moveBackAndForth)
What I want to do is, when the image is moving to the right, I want to replace the image with a different SKSpriteNode image, and when it moves back left, I want to use the original image, and repeat this forever. I am struggling with what the code should be for this.
SpriteKit comes with a SKAction, setTexture, to instantaneously change a sprite's texture with relative ease. You can create an inline SKTexture object of each images, use them in SKActions, and add them to your sequence loop, like this:
let moveRight = SKAction.moveByX(frame.size.width/2.8, y: 0, duration: 2)
let moveLeft = SKAction.moveByX(-frame.size.width/2.8, y: 0, duration: 2)
let texRight = SKAction.setTexture(SKTexture(imageNamed: "Drake1r"))
let texLeft = SKAction.setTexture(SKTexture(imageNamed: "Drake1l"))
let moveBackAndForth = SKAction.repeatActionForever(SKAction.sequence([texRight, moveRight, texLeft, moveLeft]))
Drake1.runAction(moveBackAndForth)
Hopefully this works for you! Please note that if the textures are different sizes, you must add resize: Bool to setTexture's arguments.