Sten
Sten

Reputation: 1109

How to use SpriteKit archives with SKSpriteNode subclasses

How can I use a spritekit archive file, where a SpriteNode is located, and have that SpriteNode instantiated "into" a subclass (using Swift?)

I can find the node using scene.childNodeWithName("mysprite") but I don't know how to make it into an instance of my subclass of SKSpriteNode.

Upvotes: 1

Views: 1264

Answers (2)

Anton Rogachevskyi
Anton Rogachevskyi

Reputation: 219

You can use this delegate https://github.com/ice3-software/node-archive-delegate or, for swift implementation, smt like this:

class func unarchiveNodeFromFile(file:String)-> SKNode? {
    if let path = NSBundle.mainBundle().pathForResource(file, ofType: "sks") {
        var fileData = NSData.dataWithContentsOfFile(path, options: NSDataReadingOptions.DataReadingMappedIfSafe, error: nil)
        var archiver = NSKeyedUnarchiver(forReadingWithData: fileData)
        archiver.setClass(self.classForKeyedUnarchiver(), forClassName: "SKNode")
        let node = archiver.decodeObjectForKey(NSKeyedArchiveRootObjectKey) as SKNode
        archiver.finishDecoding()
        return node
    } else {
        return nil
    }
}

Upvotes: 1

rickster
rickster

Reputation: 126127

There's no way to set a custom class for a node in the SpriteKit editor in Xcode 6. (That'd be a great feature request to file with Apple, though.)

However, the sks files you produce in Xcode are just NSKeyedArchiver archives, and you can use NSKeyedUnarchiver options to control how your objects get instantiated at load time. So there's a (limited) option for changing classes at load time — you can see this in the template code when you create a new SpriteKit Game project in Xcode 6.

See the SKNode extension (or category in the ObjC version) in GameViewController.m: it uses the NSKeyedUnarchiver method setClass(_:, forClassName:) to treat the SKScene instance in the archive as an instance of the template project's GameScene class instead. You can extend this pattern to create other custom scene classes from Xcode-created archives.

You'll notice, though, that setClass(_:forClassName:) works on a class-name basis, so it's of limited use if your archive contains several objects of the same class and you want to decode one of them as a different class than the rest. In that case, you might look into using other unarchiver tricks — for example, replacing an object in the unarchiver(_:didDecodeObject:) delegate method.

Upvotes: 5

Related Questions