简体   繁体   English

Swift,SpriteKit:如何保存场景的整体进度

[英]Swift, SpriteKit: how to save the whole progress of a scene

I have build a swift game with a "GameViewController.swift" 我用“ GameViewController.swift”构建了一个快速游戏

import UIKit
import SpriteKit

class GameViewController: UIViewController {


override func viewDidLoad() {
    super.viewDidLoad()


    if let scene = GameScene(fileNamed:"GameScene") {
        // Configure the view.
        let skView = self.view as! SKView

        /* Set the scale mode to scale to fit the window */


        scene.scaleMode = .AspectFill

        skView.presentScene(scene)
        }
    }
}

and i have a scene called "GameScene"(it is the default game-file when you open swift and create a new swift game) 我有一个名为“ GameScene”的场景(当您打开swift并创建一个新的swift游戏时,这是默认的游戏文件)

import UIKit
import SpriteKit

class GameScene: SKScene{

var building = SKSpriteNode()

override func didMoveToView(view: SKView) {

    /* Setup your scene here */

}

a lot of things going on there. 那里发生了很多事情。 (buildings can be placed and that trigger some actions and so on) (可以放置建筑物并触发某些动作等)
But all the progress is lost when you leave the app. 但是,当您离开应用程序时,所有进度都将丢失。
How to save the whole progress of this "GameScene" and reload it at the start? 如何保存此“ GameScene”的整个进度并在开始时重新加载它?

SKScene conforms to NSCoding, so you can use this to archive your scene. SKScene符合NSCoding,因此您可以使用它来存档场景。 Here is a tutorial that may help. 这是一个可能有帮助的教程。 https://www.hackingwithswift.com/read/12/3/fixing-project-10-nscoding https://www.hackingwithswift.com/read/12/3/fixing-project-10-nscoding

The basic idea is you take the instance of your scene, and you archive it with: 基本思想是您以场景的实例为例,并使用以下命令对其进行存档:

NSKeyedArchiver.archivedData(withRootObject: scene)

Then take this and save it to disk or somewhere else 然后将其保存到磁盘或其他地方

You can then unarchive it later with 然后,您可以稍后将其取消存档

NSKeyedUnarchiver.unarchiveObject(with: scene) as! SKScene

Now when you make a custom scene class, you need to be sure to include any variables you create that you need to save. 现在,当您创建自定义场景类时,您需要确保包括创建的所有需要​​保存的变量。 This is where that pesky required init(coder aDecoder:NSCoder) initializer comes in that people tend to not use. 这就是讨厌的required init(coder aDecoder:NSCoder)初始化程序出现的地方,人们往往不使用它。

You basically use this initializer to decode your custom variables, like this. 基本上,您可以使用此初始化程序来解码自定义变量,如下所示。

required init(coder aDecoder: NSCoder) {
    player = aDecoder.decodeObject(forKey: "player") as! String
}

To save it to the archive, you add an encode method 要将其保存到存档中,您可以添加编码方法

func encode(with aCoder: NSCoder) {
    aCoder.encode(player, forKey: "player")
}

You can archive your game state in the applicationDidEnterBackground(_:) event. 您可以在applicationDidEnterBackground(_ :)事件中存档游戏状态。 Subscribe through NotificationCenter to get notified. 通过NotificationCenter订阅以获得通知。

class GameScene : SKScene {
    required init?(coder decoder: NSCoder) {
        super.init(coder: decoder)

        NotificationCenter.default.addObserver(self, selector: #selector(applicationDidEnterBackground), name: .UIApplicationDidEnterBackground, object: nil)
    }

    func applicationDidEnterBackground() {
        // Save Scene
        let sceneData = NSKeyedArchiver.archivedData(withRootObject: self)
        UserDefaults.standard.set(sceneData, forKey: "currentScene")
    }

    class func loadScene() -> SKScene? {
        var scene: GameScene?

        if let savedSceneData = UserDefaults.standard.object(forKey: "currentScene") as? NSData,
           let savedScene = NSKeyedUnarchiver.unarchiveObject(with: savedSceneData as Data) as? GameScene {
            scene = savedScene
        } else {
            scene = nil
        }

        return scene
    }
}

Scene loading happens in viewDidLoad , by first attempting to locate a previously archived scene or creating a new scene if no archived scene exists. 场景加载发生在viewDidLoad ,方法是首先尝试查找先前存档的场景,或者在不存在存档场景的情况下创建一个新场景。

class GameViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        if let view = self.view as! SKView? {
            guard let scene = GameScene.loadScene() ?? SKScene(fileNamed: "GameScene") as? GameScene else {
                fatalError("Scene not loaded")
            }

            scene.scaleMode = .resizeFill

            view.presentScene(scene)            
            view.ignoresSiblingOrder = true
        }
    }
}

You'll also need to make game elements NSCoding compliant, as mentioned in other answers. 如其他答案中所述,您还需要使游戏元素符合NSCoding

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM