在一个场景中,我有这样的代码:
let defaults = NSUserDefaults.standardUserDefaults()
defaults.setInteger(score, forKey: "scoreKey")
defaults.synchronize()
当用户接触到间隙时,代码运行:
score++
如果用户撞到障碍物,GameOverScene 将接管。这是我为 GameOverScene 将分数移动到场景到场景的代码:
let defaults = NSUserDefaults.standardUserDefaults()
let score = defaults.integerForKey("scoreKey")
scoreLabel.text = "\(score)"
但是,我的代码中存在一个错误,即 scoreLabel 不更新其文本。例如,假设用户得分为 1 并死亡。当他死了,gameOverScene 会出现并说得分是 1。然后,假设用户点击重新启动,得分为 5,然后死了。在 GameOverScene 中,scoreLabel 将显示为 1。
请帮帮我!
最佳答案
如果您使用 iOS 8 或更高版本,则无需再真正调用同步。这是 Apple 推荐的,但很多人仍然这样做。因此,如果您仍然使用它,请删除该行。
我首选的游戏数据方式是使用带有 NSCoding 的单例 GameData 类。无需到处添加变量,而且更干净。我建议你读这个。
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 属性,您所有的文本标签将立即更新。不需要 userDefault 同步等。
调用 ...shared... 也将初始化助手。如果您想在游戏启动后立即加载游戏数据,您可以调用
GameData.shared
在您的 appDelegate 或 viewController 中。它可能不是真正需要的,但您仍然可以这样做,只是为了确保在游戏启动后立即初始化助手。
如果你想保存你打电话
GameData.shared.save()
请记住在 ViewDidLoad 方法中将 gameScene.swift 中的分数重置为 0。
GameData.shared.score = 0
这应该会让您的生活更轻松。如果你想使用 iCloud,你所要做的就是转到你的目标和功能并打开 iCloud 并勾选 keyValueStorage(不是核心数据)。完成。
注意: 要更进一步,您可以从 gitHub 上的 JRendel 获取 KeychainWrapper 助手。与使用 NSUserDefaults 存储编码的游戏数据相比,您使用钥匙串(keychain),它非常简单易用。
关于ios - SpriteKit : Why does it wait one round for the score to update?( swift ),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33684540/