将 GameViewController.swift 链接到 GameScene.swift

Posted

技术标签:

【中文标题】将 GameViewController.swift 链接到 GameScene.swift【英文标题】:linking GameViewController.swift to GameScene.swift 【发布时间】:2016-11-18 01:14:44 【问题描述】:

我在 main.storyboard 上创建了一个 UI 元素,我需要隐藏它,直到游戏结束并且一旦玩家点击屏幕即可关闭。 Main.storyboard 链接到 GameViewController,因此我所有的 IBOutlets 和 IBAction 都在其中,我所有的游戏代码都在 GameScene 中。我如何将视图控制器链接到场景,因为弹出图像和按钮仅在游戏结束时出现。非常感谢一些帮助,我已经坚持了很长一段时间了。

【问题讨论】:

这是 Apple 宣传的 SpriteKit 所认为的“易用性”的一个基本问题。使用起来并不容易,需要深刻理解的东西有几十个。我希望我能提供帮助,但我仍在努力探索在游戏世界中的场景、视图、视图控制器以及方法和实例之间拥有/查看/交谈的所有方式。所以不要惊慌,这似乎并不立即显而易见,并花时间阅读 CrashOverRide 和这里​​的其他一些人,因为他们知道很多,甚至不知道他们知道多少。对他们来说很容易。不知何故 @Confused 谢谢你,我很沮丧,失去了希望。我希望它会点击! CrashOverRides 方法似乎是最好的方法。我已经设法让按钮在屏幕上显示为 SKSprite 节点,同时我的游戏弹出,只是努力让共享功能工作以允许用户在社交媒体上发帖。 @Confused 检查我对这个问题的回答,尤其是前几段。希望这可以帮助您在基本层面上了解 ViewController、SKScene 之间的区别以及何时使用它们。 【参考方案1】:

这似乎是人们在使用 SpriteKit 游戏时经常遇到的问题,所以让我们来看看 SpriteKit 游戏和 UIKit 应用程序之间的区别。

当你制作一个常规的 UIKit 应用程序时,例如YouTube、Facebook,您将为您看到的每个屏幕/菜单(主屏幕、频道屏幕、订阅频道屏幕等)使用 ViewControllers、CollectionViews、Views 等。因此,您可以为此使用 UIKit API,例如 UIButtons、UIImageViews、UILabels、UIViews、UICollectionViews 等。为了直观地做到这一点,我们将使用故事板。

另一方面,在 SpriteKit 游戏中,它的工作方式有所不同。您为您看到的每个屏幕(MenuScene、SettingsScene、GameScene、GameOverScene 等)使用 SKScene,并且只有 1 个 ViewController (GameViewController)。包含 SKView 的 GameViewController 将呈现您的所有 SKScene。

因此,我们应该使用 SpriteKit API(例如 SKLabelNodes、SKSpriteNodes、SKNodes 等)直接将我们的 UI 添加到相关的 SKScene 中。要直观地做到这一点,我们将使用 SpriteKit 场景关卡编辑器而不是故事板。

所以一般逻辑是像往常一样从 GameViewController 加载您的第一个 SKScene,而不是从相关的 SKScene 中加载其余部分。除了默认代码之外,您的 GameViewController 基本上应该没有代码。您还可以非常轻松地从一个场景过渡到另一个场景(GameScene -> GameOverScene)。

如果您将 GameViewController 用于您的 UI,如果您有多个 SKScene,它会很快变得混乱,因为 UI 将被添加到 GameViewController 并因此添加到所有 SKScene。因此,当您在场景之间转换时,您将不得不删除/显示 UI,这将是疯狂的。

要在 SpriteKit 中添加标签,应该是这样的

 class GameScene: SKScene 

  lazy var scoreLabel: SKLabelNode = 
      let label = SKLabelNode(fontNamed: "HelveticaNeue")
      label.text = "SomeText"
      label.fontSize = 22
      label.fontColor = .yellow
      label.position = CGPoint(x: self.frame.midX, y: self.frame.midY)
      return label
  ()

  override func didMove(to view: SKView) 

      addChild(scoreLabel)
  
 

要制作按钮,您实际上是创建一个 SKSpriteNode 并为其命名,然后在 touchesBegan 或 touchesEnded 中查找它,并在其上运行 SKAction 以获取动画和一些代码。

enum ButtonName: String 
     case play
     case share


class GameScene: SKScene 

       lazy var shareButton: SKSpriteNode = 
            let button = SKSpriteNode(imageNamed: "ShareButton")
            button.name = ButtonName.share.rawValue
            button.position = CGPoint(x: self.frame.midX, y: self.frame.midY)
            return button
        ()

       override func didMove(to view: SKView) 

             addChild(shareButton)
       

       /// Touches began
       override open func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) 

             for touch in touches 
                 let location = touch.location(in: self)
                 let node = atPoint(location)

                 if let nodeName = node.name 
                      switch nodeName 
                      case ButtonName.play.rawValue:
                          // run some SKAction animation and some code
                      case ButtonName.share.rawValue:

                          let action1 = SKAction.scale(to: 0.9, duration: 0.2)
                          let action2 = SKAction.scale(to: 1, duration: 0.2)
                          let action3 = SKAction.run  [weak self] in
                             self?.openShareMenu(value: "\(self!.score)", image: nil) // image is nil in this example, if you use a image just create a UIImage and pass it into the method
                          
                          let sequence = SKAction.sequence([action1, action2, action3])
                          node.run(sequence)

                      default: 
                          break
                    
               
          
     
 

为了让这更容易,我会创建一个按钮帮助类,一个简单的例子看看这个 https://nathandemick.com/2014/09/buttons-sprite-kit-using-swift/

您还可以查看 Apple 的示例游戏 DemoBots,了解功能更丰富的示例。

这样您就可以在帮助类中包含动画等内容,而不必为每个按钮重复代码。

为了分享,我实际上会使用 UIActivityController 而不是那些可能很快就会被弃用的旧社交 API。这也允许您通过 1 个 UI 共享到多个服务,并且您的应用中也只需要 1 个共享按钮。在您调用它的 SKScene 中,它可能是一个像这样的简单函数。

func openShareMenu(value: String, image: UIImage?) 
    guard let view = view else  return 

    // Activity items
    var activityItems = [AnyObject]()

    // Text
    let text = "Can you beat my score " + value
    activityItems.append(text as AnyObject)

    // Add image if valid
    if let image = image 
        activityItems.append(image)
    

    // Activity controller
    let activityController = UIActivityViewController(activityItems: activityItems, applicationActivities: nil)

    // iPad settings
    if Device.isPad 
        activityController.popoverPresentationController?.sourceView = view
        activityController.popoverPresentationController?.sourceRect = CGRect(x: view.bounds.midX, y: view.bounds.midY, width: 0, height: 0)
        activityController.popoverPresentationController?.permittedArrowDirections = UIPopoverArrowDirection.init(rawValue: 0)
    

    // Excluded activity types
    activityController.excludedActivityTypes = [
        UIActivityType.airDrop,
        UIActivityType.print,
        UIActivityType.assignToContact,
        UIActivityType.addToReadingList,
    ]

    // Present
    view.window?.rootViewController?.present(activityController, animated: true)

然后在按下正确的按钮时调用它(参见上面的示例)

openShareMenu(value: "\(self.score)", image: SOMEUIIMAGE)

希望对你有帮助

【讨论】:

如果我将 gameOverPopUp 创建为 SKSpriteNode,我可以让它出现并以我想要的方式消失,但是如何在按下按钮时添加一个动作?就像按下 a 按钮时 IBAction 运行一样,我如何使用 SpriteNodes 实现相同的效果? 是的,你应该为你的 gameOver 弹出菜单使用 SKNodes/SKSpriteNodes。要添加按钮,您只需将精灵添加到 gameOverMenu 并在 touches 中查找它们开始查看按钮是否被按下,然后运行 ​​SKAction 对其进行动画处理。更好的是创建一个按钮帮助类来为你管理这个,一个简单的例子是nathandemick.com/2014/09/buttons-sprite-kit-using-swift 对于一个功能更丰富的例子,你应该看看苹果游戏 DemoBots。 我可以运行 SKAction 在 facebook 和 twitter 上发帖吗?这就是我在 ViewController 中创建 IBAction 的原因,因为在社交网络上发布使用帖子更容易 我实际上不会使用这些 API,它们比较老。对于共享,您现在应该使用 UIActivityController,您可以在其中使用 1 个 UI 共享到多个服务,并且您也只需要 1 个按钮。所以一般的想法是运行 SKAction 以在按下按钮时为您的按钮设置动画,而不是在动画完成时运行代码以呈现 UIActivityController。有很多关于 UIActivityController 的教程,只需 google 即可。要在 SpriteKit 场景中呈现诸如 UIActivityController 之类的 ViewController,您可以说 this view?.window?.rootViewController.present(...)。 我已经用更多细节更新了我的答案,包括 UIActivityController 示例。告诉我进展如何【参考方案2】:

像这样在 GameScene 类中创建 GameViewController 的引用

class GameScene: SKScene, SKPhysicsContactDelegate 

    var referenceOfGameViewController : GameViewController!


在 GameViewController 中这样传递引用

   class GameViewController: UIViewController 

       override func viewDidLoad() 
      super.viewDidLoad()

    if let view = self.view as! SKView? 
    // Load the SKScene from 'GameScene.sks'
     if let scene = GameScene(fileNamed: "GameScene") 
            // Set the scale mode to scale to fit the window
            scene.scaleMode = .aspectFill
            scene.referenceOfGameViewController = self
            // Present the scene
            view.presentScene(scene)
        


    view.ignoresSiblingOrder = true

    view.showsFPS = true
    view.showsNodeCount = true
    
  

通过使用这一行,您可以传递对 GameScene 类的引用

        scene.referenceOfGameViewController = self

现在在 GameScene 类中,您可以像这样访问 GameViewController 的所有变量

referenceOfGameViewController.fbButton.hidden = false
referenceOfGameViewController.gameOverPopUP.hidden = false

【讨论】:

当我添加:var referenceOfGameViewController = GameViewController!错误说:类型名称后的预期成员名称或构造函数调用。对于这一行:scene.referenceOfGameViewController = self 我得到错误 SKScene 类型的值没有成员'referenceOfGameViewController' 添加 var referenceOfGameViewController : GameViewController! 不要写 var referenceOfGameViewController = GameViewController!写 var referenceOfGameViewController : GameViewController! 在 GameViewController.swift 中我仍然收到一条错误消息,提示“SKScene”类型的值没有成员“referenceGameViewController”

以上是关于将 GameViewController.swift 链接到 GameScene.swift的主要内容,如果未能解决你的问题,请参考以下文章

如何将Ios文件上传到

Javascript 将正则表达式 \\n 替换为 \n,将 \\t 替换为 \t,将 \\r 替换为 \r 等等

如何将视频文件转换格式

sh 一个将生成CA的脚本,将CA导入到钥匙串中,然后它将创建一个证书并与CA签名,然后将其导入到

python怎么将0写入文件?

如何将CMD窗口背景改成透明?