UPGRADE YOUR SKILLS: Learn advanced Swift and SwiftUI on Hacking with Swift+! >>

SOLVED: Strange positioning issues with SpriteKit - what am I getting wrong?

Forums > Swift

Hi,

I've been playing about with Spritekit recently and have come across a somewhat novel issue. I've created a scene with three sprites, and can move them about happily. I then save, reset and reload, and that's where the funkiness starts - there is nothing amiss with the saving and loading functions, and everything else appears to be working well. I hope the following screenshots and explanation outline well enough what I'm talking about.

1) I generate three objects and their position is set at 0.0...

Sprites when first generated

2) I move them to the following positions...

First moved

3) I then save and reload, there is an almost imperceptible shifting of the sprites...

An imperceptible shifting

4) I then move the top sprite back to the middle of the screen...

Top sprite moved down

5) I then save and reload...and it jumps down to the bottom of the screen..!

Well, would you look at that

If I save and load without moving any of the sprites they stay in the same position.

Here is the code that I'm using:


import Foundation
import SpriteKit

class SpriteKitManager: ObservableObject {
    static let shared = SpriteKitManager()
    // Create a scene with a default size
    let scene = GameScene(size: CGSize(width: 640, height: 480))

    init(){
        // Set the scale mode to resize fill
        scene.scaleMode = .resizeFill
        scene.anchorPoint = CGPoint(x: 0.5, y: 0.5)
    }
}

class GameScene: SKScene {
    override func didMove(to view: SKView) {
        refreshAnimalSprites()
    }

    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {

    }

    func refreshAnimalSprites(){
        for child in children {
            child.removeFromParent()
        }

        for animal in animalManager.animals {
            let animalSprite = AnimalSprite(id: animal.id, animalType: animal.type)
            animalSprite.position = animal.position
            addChild(animalSprite)
        }
    }
}

class AnimalSprite : SKNode {
    var id : Int
    private var currentNode: SKNode?

    override var isUserInteractionEnabled: Bool {
        set {
            // ignore
        }
        get {
            return true
        }
    }

    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        if let touch = touches.first {
            let location = touch.location(in: self)

            let touchedNodes = self.nodes(at: location)
            for node in touchedNodes.reversed() {
                self.currentNode = node
            }
        }

    }

    override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
        if let touch = touches.first, let node = self.currentNode {
            let touchLocation = touch.location(in: self)
            // Convert the touch location to the coordinate system of the parent node
            let nodeLocation = self.convert(touchLocation, to: node.parent!)
            node.position = nodeLocation
        }
    }

    override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
        if self.currentNode != nil {
            if let animal = animalManager.animals.first(where: { $0.id == id }) {
                if let touch = touches.first, let node = self.currentNode {
                    let touchLocation = touch.location(in: self)
                    // Convert the touch location to the coordinate system of the parent node
                    let nodeLocation = self.convert(touchLocation, to: node.parent!)
                    animal.position = nodeLocation
                }
            }

            self.currentNode = nil
        }
    }

    init(id: Int, animalType: AnimalType){
        var sprite : SKNode

        switch(animalType) {
        case .dog:
            sprite = SKSpriteNode(imageNamed: "Dog" )
        case .cat:
            sprite = SKSpriteNode(imageNamed: "Cat" )
        case .owl:
            sprite = SKSpriteNode(imageNamed: "Owl" )
        case .penguin:
            sprite = SKSpriteNode(imageNamed: "Penguin" )
        case .human:
            sprite = SKSpriteNode(imageNamed: "Person" )
        default:
            sprite = SKSpriteNode(color: .red, size: CGSize(width: 50, height: 50))
        }
        self.id = id
        super.init()

        addChild(sprite)
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}

I am confident with the rest of the code, I just can't track down what I am getting wrong with my positioning. There is no scaling going on beyond the resizeFill. Whenever I move a sprite and save/reload it's almost like there's a move along the same vector, if that makes sense, and then it stays where it is.

If anyone could shed any light, I'd be grateful.

Many thanks,

Jes

3      

You mentioned the positions are off when you save and reload. Show the code you use to save and reload.

Set a breakpoint inside your save function, step through the code, and check the position of the sprites. Are the positions what you expect? If you open the file, are the sprite positions what you expect?

I see the following line of code in your touchesMoved and touchesEnded functions:

let nodeLocation = self.convert(touchLocation, to: node.parent!)

You're converting to the parent's coordinate space when someone moves. Do you convert to the parent's coordinate space when saving and reloading?

4      

Thanks for the response.

The save and load functions work exactly as expected, it's just that occaisionally it looks like the touchesEnded method doesn't fire correctly, or at least that how it appears.

I've got things mostly working now apart from that occasional glitch, so I'll just pursue that avenue.

3      

TAKE YOUR SKILLS TO THE NEXT LEVEL If you like Hacking with Swift, you'll love Hacking with Swift+ – it's my premium service where you can learn advanced Swift and SwiftUI, functional programming, algorithms, and more. Plus it comes with stacks of benefits, including monthly live streams, downloadable projects, a 20% discount on all books, and free gifts!

Find out more

Sponsor Hacking with Swift and reach the world's largest Swift community!

Reply to this topic…

You need to create an account or log in to reply.

All interactions here are governed by our code of conduct.

 
Unknown user

You are not logged in

Log in or create account
 

Link copied to your pasteboard.