Передача строки между SKScenes с использованием UserDefaults

В игре, которую я разрабатываю со 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)")
}
}

Как видите, при нажатии кнопки выбора назад имя сохраняется. Теперь это соответствующий код сцены главного меню:

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 для сохранения результатов, но не могу понять, почему это не работает в этом случае. Любая идея о том, как передавать строки между SKScenes с помощью UserDefaults? Я делаю что-то неправильно?


ПРИМЕЧАНИЕ. Хотя ответ Knight0fDragon помечен как правильный, его ответ работает для передачи строки между сценами, но не для постоянного сохранения этого значения. Если вы хотите передать значение и сохранить его, проверьте мой ответ.

2 ответа

Решение

Я бы порекомендовал не делать 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)

Обратите внимание, я не уверен, если как? Строка нужна, попробуйте ее без нее и посмотрите, сможет ли Swift сделать это

По-видимому, 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)
Другие вопросы по тегам