保存用户离开的当前级别

时间:2018-01-24 03:21:49

标签: ios swift sprite-kit skscene gameplay-kit

如何保存用户所在的当前级别。我尝试过使用该代码,但它不起作用。当用户离开游戏时,我希望游戏在他们离开的级别上进行回升。

这是在我的viewcontroller.swift文件中:

import UIKit
import SpriteKit
import GameplayKit

class GameViewController: UIViewController {

override func viewDidLoad() {
    super.viewDidLoad()

    if let view = self.view as! SKView? {

        guard let scene = GameScene.loadScene() ?? SKScene(fileNamed: "mainMenu") as? GameScene else {
            fatalError("Scene not loaded")

        }
        scene.scaleMode = .aspectFill

        view.presentScene(scene)
        view.ignoresSiblingOrder = true

        view.showsFPS = true
        view.showsNodeCount = true
    }
}

override var shouldAutorotate: Bool {
    return true
}

override var supportedInterfaceOrientations: UIInterfaceOrientationMask 
{
    if UIDevice.current.userInterfaceIdiom == .phone {
        return .allButUpsideDown
    } else {
        return .all
    }
}

override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
    // Release any cached data, images, etc that aren't in use.
}

override var prefersStatusBarHidden: Bool {
    return true
}
}

我有一个mainMenu屏幕,当用户点击屏幕时,我希望向该人显示该用户所在的最新级别。

这是在我的mainMenu.swift文件中:

import SpriteKit
import GameplayKit

var welcomeLabel = SKLabelNode()
var playLabel = SKLabelNode()

class GameScene: SKScene {
required init?(coder decoder: NSCoder) {
    super.init(coder: decoder)
    decoder.decodeBool(forKey: "savingKey")

    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
}

override func didMove(to view: SKView) {

    welcomeLabel = SKLabelNode(fontNamed: "Courier New")
    welcomeLabel.text = "Go round Go"
    welcomeLabel.fontColor = SKColor.green
    welcomeLabel.fontSize = 50
    welcomeLabel.position = CGPoint(x: frame.midX, y: 500)
    addChild(welcomeLabel)

    backgroundColor = UIColor.lightGray

    playLabel = SKLabelNode(fontNamed: "Courier New")
    playLabel.text = "Tap anywhere to play"
    playLabel.fontColor = SKColor.green
    playLabel.fontSize = 50
    playLabel.position = CGPoint(x: frame.midX, y: frame.midY)
    addChild(playLabel)
}



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

    welcomeLabel.isHidden = true
    playLabel.isHidden = true
    let nextlevel = levelOne(fileNamed: "levelOne")
    nextlevel?.scaleMode = .aspectFill
    self.view?.presentScene(nextlevel!, transition: 
SKTransition.fade(withDuration: 0.1))
    }


override func update(_ currentTime: TimeInterval) {

}
}

我想如果有人能向我解释如何做到这一点。在编码和解码方面我没有经验。

1 个答案:

答案 0 :(得分:0)

您不需要在此处使用编码和解码。您只需在用户默认值中保存当前场景的名称即可。你甚至不需要通知中心。只需在用户默认值中保存场景名称,如下所示:

class GameScene:SKScene {

    let defaults = UserDefaults.standard

    override func didMove(to view: SKView) {

        defaults.set(currentLevel, forKey: "continuePoint")

    }

}

现在在GameViewController类中检查是否有已保存的continuePoint。如果是这种情况,请加载场景。如果不是这种情况,请加载初始级别:

class GameViewController: UIViewController{

    let defaults = UserDefaults.standard

    override func viewDidLoad(){
        super.viewDidLoad()

        //Switch this with the name of your first level.
        var initialLevel = "initialLevelName"

        if defaults.object(forKey: "continuePoint") != nil{
            initialLevel = defaults.string(forKey: "continuePoint")!
        }

        if let view = self.view as! SKView? {

            if let scene = GameScene(fileNamed: initialLevel) {

                scene.scaleMode = .aspectFill
                scene.currentLevel = initialLevel

                view.presentScene(scene)
            }
        }
    }

}

不幸的是我现在无法测试这个,但是这样的话肯定会有用,我也会在游戏中使用它。

编辑:

我查看了你的项目,我发现你每次都将mainMenu.swift中的级别更改为firstLevel。你可以在touchesBegan中做这样的事情:

    var levelName = ""
    var nextLevel: SKScene?

    if defaults.object(forKey: "continuePoint") != nil && defaults.string(forKey: "continuePoint") != ""{
        levelName = defaults.string(forKey: "continuePoint")!
    }
    else{
        levelName = "levelOne"
    }      
    if levelName == "levelOne"{
        nextLevel = levelOne(fileNamed: levelName)
    }
    else if levelName == "levelTwo"{
        nextLevel = levelTwo(fileNamed: levelName)
    }
    nextLevel?.scaleMode = .aspectFill
    self.view?.presentScene(nextLevel!, transition: SKTransition.fade(withDuration: 0.1))

    }

但这不是最好的方法。问题是你有一个新的SKScene子类用于游戏中的每个级别。如果您使用.plist文件并在那里设置特定级别的属性,您可以在GameScene类中解析它,然后您只有一个SKScene类用于所有场景。你的菜单场景应该是一个单独的课程。

您应该了解如何在游戏中使用plist文件以获得更好的结构。顺便说一句:在所有项目中使用像github或bitbucket这样的源代码管理是件好事。因此,当您的项目变得更大并且您构建了新功能并且您的代码没有按预期工作时,您可以轻松地将其设置回旧状态。