【问题标题】:Passing a string between SKScenes using UserDefaults使用 UserDefaults 在 SKScene 之间传递字符串
【发布时间】:2017-06-25 18:40:07
【问题描述】:

在我使用 Swift 开发的游戏中,我希望玩家能够在类似商店的场景中选择背景,从而更改每个 SKScene 的背景。我正在尝试使用 UserDefaults 来完成此操作,但由于某种原因它不起作用。这是Shop Scene的重要代码(我删除了不相关的代码):

import SpriteKit

class ShopScene: SKScene {

var backNumber = 90
var backRemainder = 0
var background = SKSpriteNode()
var backName:String = "back1"

override func didMove(to view: SKView) {

    background.texture = SKTexture(imageNamed: "\(backName)")
    background.size = self.size
    self.addChild(background)

    let nextButton: NButton = NButton(defaultButtonImage: "next", activeButtonImage: "nextP", buttonAction: nextAction)
    addChild(nextButton)

    let selectButton: SButton = SButton(defaultButtonImage: "next", activeButtonImage: "nextP", buttonAction: selectAction)
    addChild(selectButton)   
}

func selectAction() {

    UserDefaults.standard.set(backName, forKey: "backSaved")

    let sceneToMoveTo = MainMenuScene(size: self.size)
    sceneToMoveTo.scaleMode = self.scaleMode
    let sceneTransition = SKTransition.fade(withDuration: 0.4)
    self.view!.presentScene(sceneToMoveTo, transition: sceneTransition)   
}

func nextAction() {

    backNumber += 1
    backRemainder = backNumber % 3

    switch backRemainder {
    case 0:
        backName = "back1"
    case 1:
        backName = "back2"
    case 2:
        backName = "back3"
    default:
        backName = "back1"
    }

    background.texture = SKTexture(imageNamed: "\(backName)")
}
}

如您所见,当按下选择按钮时,backName 被保存。现在,这是主菜单场景的相关代码:

Import SpriteKit

class MainMenuScene: SKScene {

var backName = UserDefaults.standard.string(forKey: "backSaved")

override func didMove(to view: SKView) {

    let background = SKSpriteNode(imageNamed: "\(backName)")
    background.size = self.size
    self.addChild(background)

按下“选择”按钮时,您应该切换到主菜单场景并看到背景是您选择的背景。但是,当我运行它时,我在白色背景中得到一个红色 X。我以前使用 UserDefaults 来保存分数,但我不知道为什么它在这种情况下不起作用。关于如何使用 UserDefaults 在 SKScene 之间传递字符串的任何想法?我做错了吗?


注意:虽然 Knight0fDragon 的答案被标记为正确,但他的答案适用于在场景之间传递字符串,但不能永久保存该值。如果您希望传递值并保存它,请检查我的答案。

【问题讨论】:

    标签: ios swift sprite-kit nsuserdefaults skscene


    【解决方案1】:

    我建议不要使用UserDefaults,这意味着你的应用程序的偏好。而是使用userData

    func selectAction() {
    
        let sceneToMoveTo = MainMenuScene(size: self.size)
        sceneToMoveTo.scaleMode = self.scaleMode
        sceneToMoveTo.userData = sceneToMoveTo.userData ?? NSMutableDictionary() //This lets us ensure userdata exists
        sceneToMoveTo.userData!["backSaved"] = backName
        let sceneTransition = SKTransition.fade(withDuration: 0.4)
        self.view!.presentScene(sceneToMoveTo, transition: sceneTransition)   
    }
    

    然后使用:

    import SpriteKit
    
    class MainMenuScene: SKScene {
    
    
    
    lazy var backName:String = {return self.userData?["backSaved"] as? String ?? "back1"}() //This allows us to load backName at the time it is needed, or assign back1 if doesn't exist
    
    override func didMove(to view: SKView) {
    
    
        let background = SKSpriteNode(imageNamed: backName)
        self.addChild(background)
    

    注意,我不确定 as?需要String,不带试试看Swift能不能推断出来

    【讨论】:

    • 我在 ShopScene 中遇到这两个错误:“无法将 '[String : AnyObject]' 类型的值转换为预期的参数类型 'NSMutableDictionary?' " 和 " 可选类型 'NSMutableDictionary?' 的值没有打开;你是不是要使用“!”或者 '?'? ”。在 MainMenuScene 上:“实例成员 'userData' 不能用于类型 'MainMenuScene'”。
    • 奇怪的是我虽然 swift 知道如何解释,但我改变了答案
    • 我遇到了新的错误,你能尝试在 swift 3 上运行它吗?谢谢。
    • 你可能已经猜到了,我在这里不小心输入了 () 而不是 {} 并打开了可选
    • 谢谢,但与我的原始代码不同,这似乎不会永久保存该值。每次打开应用程序时,它都会重置。您能否在答案中包含一种保存 backName 值的简单方法,以便我接受您的答案?很抱歉让你编辑了这么多次。
    【解决方案2】:

    显然,backName 的行为是可选的,因为它可以没有值,因此是 nil。为了使我的代码正常工作,我对 Shop Scene 进行了以下更改:

    import SpriteKit
    
    class ShopScene: SKScene {
    
    var backName:String? = UserDefaults.standard.string(forKey: "backSaved")
    
    override func didMove(to view: SKView) {
    
        if backName != nil {
            backName = UserDefaults.standard.string(forKey: "backSaved")
        } else {
            backName = "back1"
        }
    
        background.texture = SKTexture(imageNamed: "\(backName!)")
        self.addChild(background)
    

    以及对主菜单场景的这些更改:

    import SpriteKit
    
    class MainMenuScene: SKScene {
    
    var backName:String? = UserDefaults.standard.string(forKey: "backSaved")
    
    override func didMove(to view: SKView) {
    
        if backName != nil {
            backName = UserDefaults.standard.string(forKey: "backSaved")
        } else {
            backName = "back1"
        }
    
        let background = SKSpriteNode(imageNamed: "\(backName!)")
        self.addChild(background)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-08-17
      • 1970-01-01
      • 2015-10-24
      • 1970-01-01
      • 1970-01-01
      • 2012-02-03
      相关资源
      最近更新 更多