J.Treutlein
J.Treutlein

Reputation: 983

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.

Upvotes: 1

Views: 607

Answers (2)

Whirlwind
Whirlwind

Reputation: 13665

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:

  1. 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.

  2. 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

Upvotes: 2

dragoneye
dragoneye

Reputation: 701

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

Upvotes: 0

Related Questions