0

I have a function that saves all the nodes on my scene and one that will add them back (these work well while the app is open). The issue I am having is how would I go about saving that array so it can be called when the app reopens. Thanks in advance for assistance.

Added the code for my nodes to give a better idea of what im trying to accomplish

let bubble = SKShapeNode(circleOfRadius: self.frame.size.width / 12)
    bubble.position = testBubble.position
    bubble.fillColor = SKColor.black
    bubble.strokeColor = SKColor.black
    bubble.name = "bubble"
    bubble.physicsBody = SKPhysicsBody(circleOfRadius: bubble.frame.height / 2)
    bubble.zPosition = 2

let bubbleLabel = SKLabelNode(text: "Bubble")
    bubbleLabel.fontColor = UIColor.darkGray
    bubbleLabel.fontSize = 10
    bubbleLabel.fontName = "MarkerFelt-Thin"
    bubbleLabel.position.y = bubble.frame.size.width / 2 -bubble.frame.size.height / 1.65
    bubbleLabel.zPosition = 3

    self.addChild(bubble)
    bubble.addChild(bubbleLabel)

@objc func saveAllNodes() {
    nodeArray.removeAll()
    for node in self.children {
        nodeArray.append(node)
    }
}  

@objc func addAllNodes() {
    self.removeAllChildren()
    for node in nodeArray {
        self.addChild(node)
    }
}

2 Answers2

0

You are probably looking at using CoreData or UserDefaults. and have the nodes load up in the AppDelegate when the app enters foreground OR (probably better) in the viewdidload function of wherever you need it.
You can use transformables in the xdatamodel for you NodeArrays and declare it as @NSManaged var [NodeArray]

dvd.Void
  • 339
  • 1
  • 5
  • 21
0

Do not bother with CoreData or UserDefaults, SKNodes conforms to NSCoding for a reason, so use KeyedArchiver instead. When your app closes, just save the scene itself, and when your app opens, reload it.

Note this is for Swift 3, not sure how much has changed in Swift 4 with Codable, but the idea should still be the same.

extension SKNode
{
    func getDocumentsDirectory() -> URL 
    {
        let paths = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
        return paths[0]
    }


    func save()
    {
        let fullPath = getDocumentsDirectory().appendingPathComponent(name)

        let data = NSKeyedArchiver.archivedData(withRootObject: scene)

        do 
        {
            try data.write(to: fullPath)
        }
        catch 
        {
            print("Couldn't write file")
        }
    }

    static func load(name:String) -> SKNode?
    {

        let fullPath = SKScene.getDocumentsDirectory().appendingPathComponent(name)

        guard let node = NSKeyedUnarchiver.unarchiveObject(withFile: fullPath.absoluteString) as? SKNode 
        else 
        {
            return nil
        }
        return node
    }
}

then to use it, when you need to save your scene, just call save() inside your scene file, and to load it call

guard let scene = SKNode.load("*myscenename*") as? SKScene
else
{
  //error out somehow
}
view.presentScene(scene)

To extend beyond the normal functionality of NSCoding, you need to also implement encode and decode. This is for when you custom class some thing and you add variables

to encode:

func encode(with coder:NSCoder)
{
    coder.encode(variable, forKey:"*variable*")
}

to decode:

required init(coder decoder:NSCoder)
{
    super.init(coder:decoder)
    if let variable = decoder.decodeObject(forKey:"*variable*") as? VariableType
    {
        self.variable = variable
    }
}
Knight0fDragon
  • 16,609
  • 2
  • 23
  • 44