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

时间:2018-10-04 15:24:10

标签: ios swift sprite-kit skscene

我一直在遵循Ray Wenderlich的旧教程:https://www.raywenderlich.com/1514-introduction-to-the-sprite-kit-scene-editor,遇到了问题。我已经多次遇到这个问题,甚至在stackoverflow网站上找到了一个“解决方案”:Passing Data Between Scenes (SpriteKit)

这是与教程相同的代码(进行了一些调整,与在Swift 2中编写的一样)。我觉得这是一个非常简单的解决方案,并且没有使用NSdefaults等代码。

这是对新场景的调用,请注意 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 问题中建议的“解决方案”也是如此。

如果是这样,那么现在实现这一目标的最佳方法是什么?

2 个答案:

答案 0 :(得分:1)

声音的问题是您在调用sceneDidLoad之后设置了变量(在初始化期间发生),因此声音不会播放。

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

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

}

在这里看不到崩溃的实际问题。

SKTransition会在您使用SKLightNode时出现问题,因此通过调用具有过渡效果的场景会使其崩溃。 SKTransition一直被引入Metal所困扰,因此您唯一可以做的就是向Apple报告,并祈祷他们没有告诉您这是故意的。

到目前为止,请跟踪所有光源,并在过渡时将isEnabled属性设置为false

您可能需要先创建场景的屏幕快照,然后再禁用光源以使其看起来不傻。

答案 1 :(得分:0)

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

您可以使用UserDefaults

func gameOver(didWin: Bool) {
   let menuScene = MenuScene(size: self.size)
   menuScene.scaleMode = .aspectFill
   let soundToPlay = didWin ? "fear_win.mp3" : "fear_lose.mp3"
   UserDefaults.standard.set(soundToPlay, forKey: "soundToPlay")
   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 = UserDefaults.standard.string(forKey: "soundToPlay") {
         run(SKAction.playSoundFileNamed(soundToPlay, waitForCompletion: false))
      }
}

然后,将其放入您的AppDelegate的applicationWillTerminate函数中:

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应用程序时我一直为此而苦恼,而我只是这样做了。因此,如果其他人有更好的答案,也请通知我!