保存用户离开的当前级别
saving the current level the user leaves off at
如何保存用户当前所在的级别。我试过使用休闲代码,但它不起作用。当用户离开游戏时,我希望游戏恢复到他们离开时的水平。
这在我的 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.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) {
}
}
我希望有人可以向我解释如何执行此操作。对编解码没有经验
此处不需要使用编码和解码。您可以将当前场景的名称保存在用户默认值中。您甚至不需要通知中心。只需将场景名称保存在用户默认值中,如下所示:
class GameScene:SKScene {
let defaults = UserDefaults.standard
override func didMove(to view: SKView) {
defaults.set(currentLevel, forKey: "continuePoint")
}
}
现在在你的 GameViewController 中 class 检查是否有保存的 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 subclass。如果您使用 .plist 文件并在那里设置特定级别的属性,您可以在您的 GameScene class 中解析它,然后您的所有场景只有一个 SKScene class。不过,您的菜单场景应该在单独的 class 中。
您应该了解如何在游戏中使用 plist 文件以获得更好的结构。顺便说一句:最好在所有项目中使用 github 或 bitbucket 等源代码管理。因此,当您的项目变得更大并且您构建了新功能并且您的代码无法按预期工作时,您可以轻松地将其设置回旧状态。
如何保存用户当前所在的级别。我试过使用休闲代码,但它不起作用。当用户离开游戏时,我希望游戏恢复到他们离开时的水平。
这在我的 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.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) {
}
}
我希望有人可以向我解释如何执行此操作。对编解码没有经验
此处不需要使用编码和解码。您可以将当前场景的名称保存在用户默认值中。您甚至不需要通知中心。只需将场景名称保存在用户默认值中,如下所示:
class GameScene:SKScene {
let defaults = UserDefaults.standard
override func didMove(to view: SKView) {
defaults.set(currentLevel, forKey: "continuePoint")
}
}
现在在你的 GameViewController 中 class 检查是否有保存的 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 subclass。如果您使用 .plist 文件并在那里设置特定级别的属性,您可以在您的 GameScene class 中解析它,然后您的所有场景只有一个 SKScene class。不过,您的菜单场景应该在单独的 class 中。
您应该了解如何在游戏中使用 plist 文件以获得更好的结构。顺便说一句:最好在所有项目中使用 github 或 bitbucket 等源代码管理。因此,当您的项目变得更大并且您构建了新功能并且您的代码无法按预期工作时,您可以轻松地将其设置回旧状态。