SpriteKit:为什么等待一轮比分才能更新? (迅速) [英] SpriteKit: Why does it wait one round for the score to update? (Swift)

查看:62
本文介绍了SpriteKit:为什么等待一轮比分才能更新? (迅速)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

In one scene, I have this code:

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

defaults.synchronize()

当用户与间隙联系时,代码运行:

When the user makes contact with the gap, the code runs:

 score++

如果用户遇到障碍物,GameOverScene将接管。以下是GameOverScene将得分移动到场景的代码:

If the user hits an obstacle, the GameOverScene takes over. Here's the code I have for the GameOverScene to move the score to scene to scene:

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

但是,我的代码中有一个错误,其中scoreLabel不会更新其文本。例如,假设用户得分为1并且死亡。当他去世时,gameOverScene会出现并说得分为1.然后,让我们说用户点击重启,然后得分5然后就死了。在GameOverScene中,scoreLabel会说1。

However, there's a bug in my code where the scoreLabel doesn't update its text. For example, let's say a user scores 1 and dies. When he dies, the gameOverScene will come up and say that the score was 1. Then, lets say the user clicks restart, and scores 5 and then dies. In the GameOverScene, the scoreLabel will say 1.

请帮助我!

推荐答案

如果您使用iOS 8或更高版本,则无需再真正调用同步。这是Apple推荐的,但很多人仍然这样做。如果你还在使用它,那就去除那条线。

You don't need to really call synchronise anymore if you use iOS 8 or above. This is recommended by Apple, yet a lot of people still do it. So get rid of that line if you still use it.

我对游戏数据的首选方法是使用带有NSCoding的单例GameData类。无需在整个地方添加变量,更清洁。我建议你读这个。

My preferred way for game data is using a singleton GameData class with NSCoding. No need to add variables all over the place and much cleaner. I advise you reading this.

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

你也可以通过这种方式集成iCloud键值存储,它非常容易,因为它类似于用户默认值(参见下面的例子)

You can also integrate iCloud key value storage that way, it is very easy as its similar to user defaults (see my example below)

无论如何,在这里开始你的是一个简单的例子,说明它的外观。

Anyway to start you off here is a simple example of how this could look.

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属性你可以说

Now in any scene if you want to use the score or saved highScore property you for example could say

GameData.shared.score++

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

如果转换到新场景或更新.text属性,所有文本标签将立即更新。不需要userDefault同步等。

All your text labels will be updated immediately if you transition to a new scene or update the .text property. No need for userDefault sync etc.

调用... shared ...也会初始化帮助程序。如果您想在游戏启动后立即加载gameData,您可以致电

Calling ...shared... will also initialise the helper. If you want to load gameData as soon as your game has launched you could call

GameData.shared

。它可能不是真的需要,但你仍然可以这样做,只是为了确保一旦游戏启动就帮助初始化。

in your appDelegate or viewController. Its probably not really needed but your could still do it just to ensure the helper is initialised as soon as the game is launched.

如果你想保存你的电话

GameData.shared.save()

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

Just remember to reset the score back to 0 in your gameScene.swift in the ViewDidLoad method.

GameData.shared.score = 0

这会让你的生活更轻松。如果你想使用iCloud,你所要做的就是转到你的目标和功能,然后打开iCloud并勾选keyValueStorage(不是核心数据)。完成。

This should make your life much easier. If you want to use iCloud all you have to do is go to your target and capabilities and turn on iCloud and tick keyValueStorage (not core data). Done.

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

Note: To take it even a step further you could get the KeychainWrapper helper from JRendel on gitHub. Than instead of using NSUserDefaults to store the encoded gameData you use keychain, its dead simple to use.

这篇关于SpriteKit:为什么等待一轮比分才能更新? (迅速)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆