SpriteKit:为什么要等一分钟才能更新分数? (迅速)

在一个场景中,我有这样的代码:

let defaults = NSUserDefaults.standardUserDefaults() defaults.setInteger(score, forKey: "scoreKey") defaults.synchronize() 

当用户与间隙接触时,代码运行:

  score++ 

如果用户遇到障碍,GameOverScene将接pipe。 以下是我为GameOverScene将分数移至场景的代码:

 let defaults = NSUserDefaults.standardUserDefaults() let score = defaults.integerForKey("scoreKey") scoreLabel.text = "\(score)" 

但是,在我的代码中,scoreLabel没有更新文本。 例如,让我们说一个用户得分1并死亡。 当他去世的时候,gameOverScene会出现,并说分数是1.然后,让用户点击重新启动,然后得分5,然后死亡。 在GameOverScene中,scoreLabel会说1。

请帮帮我!

如果您使用iOS 8或更高版本,则不需要再调用同步。 这是苹果推荐的,但很多人仍然这样做。 所以,如果你仍然使用它,那就摆脱那条线。

我最喜欢的游戏数据的方式是使用NSCoding的单身GameData类。 没有必要在所有地方添加variables,更清洁。 我build议你阅读这个。

http://www.raywenderlich.com/63235/how-to-save-your-game-data-tutorial-part-1-of-2

您还可以通过这种方式集成iCloud的密钥值存储,这很容易,因为它与用户默认值类似(请参阅下面的示例)

无论如何,从这里开始你是一个简单的例子,看看这可能。

 import Foundation /// Keys private struct Key { static let encodedData = "encodedData" static let highScore = "highScore" } class GameData: NSObject, NSCoding { // MARK: - Static Properties /// Shared instance static let shared: GameData = { if let decodedData = UserDefaults.standard.object(forKey: Key.encodedData) as? GameData { return gameData } else { print("No data, creating new") return GameData() } } // MARK: - Properties /// Defaults private let localDefaults = UserDefaults.standard private let iCloudDefaults = NSUbiquitousKeyValueStore.default() /// Progress (not saved, no need for saving the score because of the highScore var. Still have here for global single access) var score = 0 /// Progress (saved) var highScore = 0 // MARK: - Init private override init() { super.init() print("GameData init") NotificationCenter.default.addObserver(self, selector: #selector(updateFromCloud), name: NSUbiquitousKeyValueStore.didChangeExternallyNotification, object: iCloudDefaults) iCloudDefaults.synchronize() } // MARK: - Convenience Init convenience required init?(coder decoder: NSCoder) { self.init() print("GameData convenience init") // Progress highScore = decoder.decodeInteger(forKey: Key.highScore) } // MARK: - Encode func encodeWithCoder(encoder: NSCoder) { // Progress encoder.encodeInteger(highScore, forKey: Key.highScore) // MARK: - User Methods /// Save func save() { if score > highScore { highScore = score } saveLocally() saveToCloud() } // MARK: - Internal Methods /// Save locally private func saveLocally() { let encodedData = NSKeyedArchiver.archivedDataWithRootObject(self) localDefaults.setObject(encodedData, forKey: Key.encodedData) } /// Save to icloud private func saveToCloud() { print("Saving to iCloud") // Highscores if (highScore > iCloudDefaults.objectForKey(Key.highScore) as? Int ?? Int()) { iCloudDefaults.setObject(highScore, forKey: Key.highScore) } /// Update from icloud func updateFromCloud() { print("Updating from iCloud") // Highscores highScore = max(highScore, iCloudDefaults.object(forKey: Key.highScore) as? Int ?? Int()) // Save saveLocally() } 

现在在任何情况下,如果你想使用分数或保存highScore属性,你可以说

 GameData.shared.score++ 

要么

 scoreLabel.text = "\(GameData.shared.score)" highScoreLabel.text = "\(GameData.shared.highScore)" 

如果您转换到新场景或更新.text属性,所有文本标签将立即更新。 无需用户默认同步等

调用…共享…也将初始化帮手。 如果您希望在游戏启动后立即加载gameData,则可以调用

 GameData.shared 

在你的appDelegate或viewController。 它可能不是真的需要,但你仍然可以这样做,只是为了确保助手在游戏启动后立即初始化。

如果你想救你打电话

 GameData.shared.save() 

只需记住在ViewDidLoad方法的gameScene.swift中将分数重置为0。

 GameData.shared.score = 0 

这应该让你的生活变得更容易 如果您想使用iCloud,您只需转到您的目标和function,打开iCloud并勾选keyValueStorage(不是核心数据)即可。 完成。

注意:为了更进一步,您可以从gitHub上的JRendel获得KeychainWrapper助手。 而不是使用NSUserDefaults来存储你使用钥匙串编码的gameData,它的死亡简单易用。

你可以保存你的分数,如下面的代码:

 NSUserDefaults.standardUserDefaults().setInteger(score, forKey: "scoreKey") 

然后你可以得到你的分数被保存下面的代码:

  if NSUserDefaults.standardUserDefaults().objectForKey("scoreKey") != nil { score = NSUserDefaults.standardUserDefaults().objectForKey("scoreKey") as! Int } scoreLabel.text = "\(score)" 

要回答关于使用全球结构的评论的问题…

根据文档:

全局variables是在任何函数,方法,闭包或types上下文之外定义的variables。

意味着你应该在任何文件的顶部导入语句之后立即定义你的结构。

你做了一个像我发布在评论中的链接指向的结构,像这样(我把结构定义放在GameScene.swift文件中):

 struct GlobalData { static var gold = 0; static var coins = 0; static var lives = 0; static var score = 0; } 

这个结构也可以在GameOverScene中使用。 所以,在过渡之前,你会做一些事情:

 GlobalData.score = 20 GlobalData.coins = 10 //etc. 

在你的GameOverScene中,你可以像这样访问它:

 scoreNode.text = String(GlobalData.score)//scoreNode is SKLabelNode