Ios 在SpriteKit场景之间传递数据(Swift)

Ios 在SpriteKit场景之间传递数据(Swift),ios,swift,sprite-kit,skscene,Ios,Swift,Sprite Kit,Skscene,我一直在遵循Ray Wenderlich的老教程:并且遇到了一个问题。我多次遇到这个问题,甚至在stackoverflow网站上找到了一个“解决方案”: 这是与教程相同的代码(与Swift 2中编写的代码相比有一些调整)。我觉得这是一个非常简单优雅的解决方案,并没有使用NSDEFAULT等完整的代码 这是对新场景的调用,请注意soundToPlay对象: func gameOver(didWin: Bool) { let menuScene = MenuScene(size: self.s

我一直在遵循Ray Wenderlich的老教程:并且遇到了一个问题。我多次遇到这个问题,甚至在stackoverflow网站上找到了一个“解决方案”:

这是与教程相同的代码(与Swift 2中编写的代码相比有一些调整)。我觉得这是一个非常简单优雅的解决方案,并没有使用NSDEFAULT等完整的代码

这是对新场景的调用,请注意soundToPlay对象:

func gameOver(didWin: Bool) {
   let menuScene = MenuScene(size: self.size)
   menuScene.scaleMode = .aspectFill
   menuScene.soundToPlay = didWin ? "fear_win.mp3" : "fear_lose.mp3"
   let transition = SKTransition.flipVertical(withDuration: 1.0)
   self.view?.presentScene(menuScene, transition: transition)
}
这就是我所说的场景:

import SpriteKit

class MenuScene: SKScene {

   var soundToPlay: String!

   override func sceneDidLoad() {

      self.backgroundColor = SKColor(red: 0, green:0, blue:0, alpha: 1)

      // Setup label
      let label = SKLabelNode(fontNamed: "AvenirNext-Bold")
      label.text = "Press anywhere to play again!"
      label.fontSize = 55
      label.horizontalAlignmentMode = .center
      label.position = CGPoint(x: self.frame.midX, y: self.frame.midY)

      addChild(label)

      // Play sound
      if let soundToPlay = soundToPlay {
         run(SKAction.playSoundFileNamed(soundToPlay, waitForCompletion: false))
      }
}
永远不会传递数据,并且对象的值为nil

我怀疑这在Swift中已经发生了变化,因为本教程和上一个stackoverflow问题上建议的“解决方案”都非常陈旧


如果是这种情况,现在实现这一点的最佳方法是什么?

您正在做的是,当您重新加载场景时(
让menuScene=menuScene(size:self.size)
),您正在重置所有定义的变量

你可以做的是使用:

以及:

然后,将其放入AppDelegate的
应用程序willTerminate
函数中:

func applicationWillTerminate(_ application: UIApplication) {
    // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
    UserDefaults.standard.removeObject(forKey: "soundToPlay")
}
如果未将其放入AppDelegate中,则soundToPlay将在完全关闭应用后保留


我不知道
UserDefaults
是否是最好的方法,但我在制作
iOS
应用程序时一直在努力解决这个问题,我就是这么做的。所以如果其他人有更好的答案,也请通知我

声音的问题在于,您在调用sceneDidLoad后设置了变量(这在init期间发生),因此声音不会播放

要解决此问题,请在
didMove
方法中执行此代码:

override func didMove(to view: SKView) {
    guard let soundToPlay = soundToPlay else {fatalError("Unable to find soundToPlay")}
    run(SKAction.playSoundFileNamed(soundToPlay, waitForCompletion: false))

}
您崩溃的实际问题在此不可见

当您使用
SKLightNode
时,
SKTransition
会出现错误,因此通过调用带有转换的场景,它将崩溃
SKTransition
s一直被金属的引入所困扰,所以你唯一能做的就是向苹果报告,祈祷他们不会告诉你这是故意的

从现在开始,跟踪所有光源,当您转换时,将
isEnabled
属性设置为
false


在禁用光源之前,您可能需要创建场景的屏幕截图,以使其看起来不那么愚蠢。

您好,感谢您的快速响应。有两点,我希望避免使用UserDefaults,因为我相信代码应该可以工作是有原因的。当然,两个来源(Ray Wenderlich和Stackoverflow)不可能是错误的。其次,我在重置后设置soundToPlay对象,就像我对scaleMode所做的那样,scaleMode对象数据不受影响地传递。不管怎样,如果我没有得到答案,我将使用你的有用的建议UserDefaults@GaryNials当然如果有更好的答案,请通知我,以便我可以使用它!除非您计划保存到硬盘,否则不应使用userdefaults。实际上,我不鼓励将其用于设置以外的任何其他用途。我建议使用
userData
@Knight0fDragon哦。。。
userData
是否作为
userDefaults
的某种RAM版本工作?有趣的是…Userdata是您想要附加到节点的自定义数据。还有什么可以访问soundToPlay的吗?从我看到的情况来看,它不应该让你失望,所以要么你有一个不同的MenuScene,要么其他东西正在访问soundToPlay。顺便说一句,您可以使用
userData
并避免为菜单创建自定义类。除非您计划添加功能,否则请避免自定义类。有一个怪癖,由于一个糟糕的教程,我感到厌烦<代码>让menuScene=menuScene(大小:self.size);menuScene.scaleMode=.aspectFill是难看的代码。我建议设置一个恒定的静态大小或加载一个SKS文件。当您能够创建聊天室时,我可以解释原因。2) 我刚刚检查过,它只用于我剪切粘贴的代码。这是一个非常基本的游戏,它教会了如何使用场景编辑器,不幸的是,一个场景编辑器bug在向ColorSpritodes添加纹理时遇到问题,导致我编写了所有精灵的代码,而不是场景编辑器。你的其他评论很有趣,因为所有教程(我也做了不少)都有你指出的难看代码。在我的无知中,我避免使用SKS文件,并尝试以编程方式完成所有工作。谢谢,很多教程都会犯同样的错误。不幸的是,他们更关心的是如何工作,而不是如何充分利用API。是的,一旦你学会了一些基本知识,拥有一个能列出swift惯例和最佳编程实践的网站会很好。我在苹果电脑上自学了“人人都能编写代码”,并花了更多的时间来解决教程中引入的bug。谢天谢地StackOverflow无论如何,在ScenedLoad中添加一个print语句来检查它被调用了多少次非常感谢,添加didMove来查看修复了这个问题
func applicationWillTerminate(_ application: UIApplication) {
    // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
    UserDefaults.standard.removeObject(forKey: "soundToPlay")
}
override func didMove(to view: SKView) {
    guard let soundToPlay = soundToPlay else {fatalError("Unable to find soundToPlay")}
    run(SKAction.playSoundFileNamed(soundToPlay, waitForCompletion: false))

}