4

When I tried to add different scenes to my game in Swift, I encountered the method unarchiveFromFile. The problem with this method is that it only works with the GameScene class. If you call it from

extension SKNode {
    class func unarchiveFromFile(file : NSString) -> SKNode? {
        if let path = NSBundle.mainBundle().pathForResource(file, ofType: "sks") {
            var sceneData = NSData.dataWithContentsOfFile(path, options: .DataReadingMappedIfSafe, error: nil)
            var archiver = NSKeyedUnarchiver(forReadingWithData: sceneData)

            archiver.setClass(self.classForKeyedUnarchiver(), forClassName: "SKScene")
            let scene = archiver.decodeObjectForKey(NSKeyedArchiveRootObjectKey) as GameScene 
            archiver.finishDecoding()
            return scene
        } else {
            return nil
        }
    }
}

class GameViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        if let scene = GameScene.unarchiveFromFile("GameScene") as? GameScene {
             let skView = self.view as SKView
             skView.ignoresSiblingOrder = true
             skView.presentScene(scene)
        }
        // This won't work for MenuScene.unarchiveFromFile("MenuScene") as? MenuScene
        // nor MenuScene.unarchiveFromFile("MenuScene") as? GameScene

To be able to work with other SKScenes I changed all occurrences of the class GameScene to SKScene. While it now works with other SKScene classes I still don't understand what it is.

What is it this method for? should I keep it?

lisovaccaro
  • 32,502
  • 98
  • 258
  • 410

2 Answers2

3

I haven't used Xcode 6 much, but here is my understanding (someone may correct me or expound) :

This is how your app utilizes the layout data etc for the GameScene (or any SKScene). If you click on the GameScene.sks file in the Project Navigator panel you get a visual editor for your GameScene.

If you want this layout data to be utilized, you would use that method. You can visually layout your GameScene in the scene editor without need to code locations, settings etc.

prototypical
  • 6,731
  • 3
  • 24
  • 34
  • I see, everything on the game is mostly dynamic so I couldn't really get what .sks files were for and simply deleted them. I'll keep this in mind if I decide to use them. – lisovaccaro Aug 24 '14 at 04:03
  • If you look thorough the elements you can drag/drop onto the scene and modify the settings for a given element, I think you might find it useful. Things like emitters, springs, gravity fields, turbulence fields etc. It seems pretty promising, although it seems certain things don't work in the beta version I had. (or I was missing something in terms of settings) – prototypical Aug 24 '14 at 04:19
  • 1
    If you were to developed the Angry Birds game, you might start by building the different levels all in code. You would need to set the background, select and position the birds to be launched, build the structure(s) that protects the pigs, and position the pigs in the appropriate locations. Imagine doing this all in code for 100 levels. Apple provided a means to set up your levels graphically with SpriteKit Template and SpriteKit Editor. Together, they allow you to separate scene content (GameScene.sks) from game logic (GameScene.m). – 0x141E Aug 24 '14 at 08:36
  • 1
    I understand. I was going to try to implement a tilemap. Is it practical to create the game map using the sks files?? – lisovaccaro Aug 25 '14 at 00:15
3

Following on from 0x141E's comment, you can change the unarchiveFromFile method to use generics so you can use it for different SKS or SKScene classes:

extension SKNode {
    class func unarchiveFromFile<T:SKScene>(file : NSString) -> T? {
        if let path = NSBundle.mainBundle().pathForResource(file, ofType: "sks") {
            var sceneData = NSData(contentsOfFile: path, options: .DataReadingMappedIfSafe, error: nil)!
            var archiver = NSKeyedUnarchiver(forReadingWithData: sceneData)

            archiver.setClass(self.classForKeyedUnarchiver(), forClassName: "SKScene")
            let scene = archiver.decodeObjectForKey(NSKeyedArchiveRootObjectKey) as T
            archiver.finishDecoding()
            return scene
        } else {
            return nil
        }
    }
}

Just call it the same way but with the different scene content you want in there and it should work fine

if let scene = GameScene.unarchiveFromFile("Level1Scene") as? GameScene {
...

if let scene = GameScene.unarchiveFromFile("Level2Scene") as? GameScene {
...
ubersnack
  • 512
  • 6
  • 19