【问题标题】:Passing data between SpriteKit scenes (Swift)在 SpriteKit 场景之间传递数据 (Swift)
【发布时间】:2018-10-04 15:24:10
【问题描述】:

我一直在学习旧的 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 问题中建议的“解决方案”一样。

如果是这样,现在最好的方法是什么?

【问题讨论】:

  • 还有什么东西可以访问 soundToPlay 吗?从我所看到的情况来看,它不应该对你失败,所以要么你有不同的 MenuScene,要么有其他东西正在访问 soundToPlay。顺便说一句,您可以使用userData 并避免为您的菜单创建自定义类。除非您计划添加功能,否则请避免使用自定义类。由于教程不好,有一个怪癖让我很恼火。 let menuScene = MenuScene(size: self.size); menuScene.scaleMode = .aspectFill 是丑陋的代码。我建议设置一个恒定的静态大小或加载一个 SKS 文件。当您能够创建聊天室时,我可以解释原因。 2)
  • 我刚刚检查过,它只用于我剪切和粘贴的代码。这是一个非常基本的游戏,它教如何使用场景编辑器,不幸的是,场景编辑器错误导致我在向颜色精灵节点添加纹理时遇到问题,导致我编写所有精灵而不是场景编辑器。您的其他评论很有趣,因为所有教程(我已经做了很多)都有您指出的丑陋代码。在我的无知中,我避免使用 SKS 文件并尝试以编程方式完成所有操作。谢谢
  • 很多教程都犯了同样的错误。不幸的是,他们更关心让事情正常工作,而不是充分利用 API。即使是官方的苹果样品也有罪。
  • 是的,一旦您了解了基础知识,如果有一个网站可以列出快速约定和最佳编程实践,那就太好了。我从 Apple 自学了每个人都可以编写代码,并花更多时间解决按照教程引入的错误。谢天谢地,stackoverflow
  • 不管怎样,在你的sceneDidLoad中添加一个打印语句来检查它被调用了多少次

标签: ios swift sprite-kit skscene


【解决方案1】:

你的声音的问题是你在调用 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))

}

您的崩溃的实际问题在这里不可见。

SKTransitions 在你使用SKLightNode 时会被窃听,所以通过调用带有过渡的场景,它会崩溃。 SKTransitions 一直被 Metal 的引入所困扰,所以你唯一能做的就是向苹果报告,并祈祷他们不会告诉你这是故意的。

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

您可能需要在禁用光源之前创建场景的屏幕截图,以免它看起来很傻。

【讨论】:

  • 非常感谢,添加 didMove 查看已解决问题
【解决方案2】:

您所做的是,当您重新加载场景 (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 应用程序时一直在努力解决这个问题,我只是这样做了。所以如果其他人有更好的答案,也请通知我!

【讨论】:

  • 您好,感谢您的快速回复。有几点,我想避免使用 UserDefaults,因为我相信代码应该可以工作是有原因的。肯定有两个来源(Ray Wenderlich 和 Stackoverflow)不会错。其次,我在重置后设置 soundToPlay 对象,就像我对 scaleMode 所做的那样,并且 scaleMode 对象数据不受影响地传递。无论哪种方式,如果我没有得到答案,我将使用您对 UserDefaults 的有用建议
  • @GaryNials 当然。如果发布了更好的答案,请通知我,以便我使用它!
  • 除非您打算保存到硬盘,否则不应使用 userdefaults。我实际上不鼓励将它用于设置以外的任何东西。我推荐使用userData
  • @Knight0fDragon 哦...userData 可以作为userDefaults 的某种 RAM 版本工作吗?有趣...
  • Userdata 是您要附加到节点的自定义数据
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-10-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多