如何在 GameScene 中从 ViewController 调用方法

Posted

技术标签:

【中文标题】如何在 GameScene 中从 ViewController 调用方法【英文标题】:How to call method from ViewController in GameScene 【发布时间】:2015-01-28 04:07:43 【问题描述】:

我的 viewController 中有一个自定义 segue 的方法,如下所示:

func gameOver() 
    performSegueWithIdentifier("GameOver", sender: nil)

我在 GameScene.swift 中这样调用方法:

 GameViewController().gameOver()

我仔细检查了 segue 名称,它是正确的。每当我在我的 GameScene.swift 文件中调用它时,我都会收到 SIGABRT 消息,但我不知道为什么。我尝试仅使用 println() 消息调用该函数并且它有效。

任何关于为什么会发生这种情况以及如何成功调用 GameScene.swift 文件中的方法的建议将不胜感激。

谢谢!

附:这是崩溃日志:

2015-01-28 21:59:46.181 RunawaySquare[95616:3907041] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Receiver (<RunawaySquare.GameViewController: 0x7fe4305c7890>) has no segue with identifier 'GameEnd''
*** First throw call stack:
(
    0   CoreFoundation                      0x000000010d461f35 __exceptionPreprocess + 165
    1   libobjc.A.dylib                     0x000000010f39ebb7 objc_exception_throw + 45
    2   UIKit                               0x000000010e20dd3b -[UIViewController shouldPerformSegueWithIdentifier:sender:] + 0
    3   RunawaySquare                       0x000000010d2683b2 _TFC13RunawaySquare18GameViewController8gameOverfS0_FT_T_ + 914
    4   RunawaySquare                       0x000000010d261af0 _TFC13RunawaySquare9GameScene12touchesBeganfS0_FTCSo5NSSet9withEventCSo7UIEvent_T_ + 1808
    5   RunawaySquare                       0x000000010d261c3f _TToFC13RunawaySquare9GameScene12touchesBeganfS0_FTCSo5NSSet9withEventCSo7UIEvent_T_ + 79
    6   SpriteKit                           0x000000010df4d7e1 -[SKView touchesBegan:withEvent:] + 946
    7   UIKit                               0x000000010e12d16e -[UIWindow _sendTouchesForEvent:] + 325
    8   UIKit                               0x000000010e12dc33 -[UIWindow sendEvent:] + 683
    9   UIKit                               0x000000010e0fa9b1 -[UIApplication sendEvent:] + 246
    10  UIKit                               0x000000010e107a7d _UIApplicationHandleEventFromQueueEvent + 17370
    11  UIKit                               0x000000010e0e3103 _UIApplicationHandleEventQueue + 1961
    12  CoreFoundation                      0x000000010d397551 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 17
    13  CoreFoundation                      0x000000010d38d41d __CFRunLoopDoSources0 + 269
    14  CoreFoundation                      0x000000010d38ca54 __CFRunLoopRun + 868
    15  CoreFoundation                      0x000000010d38c486 CFRunLoopRunSpecific + 470
    16  GraphicsServices                    0x000000011480e9f0 GSEventRunModal + 161
    17  UIKit                               0x000000010e0e6420 UIApplicationMain + 1282
    18  RunawaySquare                       0x000000010d26cbee top_level_code + 78
    19  RunawaySquare                       0x000000010d26cc2a main + 42
    20  libdyld.dylib                       0x000000010fb8a145 start + 1
)
libc++abi.dylib: terminating with uncaught exception of type NSException

它说没有segue id。带有“GameEnd”,但有一个,如果在视图控制器上使用它就可以工作

【问题讨论】:

您是否收到有关调试器的任何崩溃报告? "以未捕获的 NSException 类型异常终止" 这是插座连接等问题的常见消息。 请贴出完整的日志以便我理解 我发布了崩溃日志 【参考方案1】:

这不起作用的原因是您正在创建GameViewController 的新实例,然后您正在调用gameOver。你真正想做的是引用你现有的GameViewController

有几种方法可以做到这一点,我举一个例子。

将 viewController 属性添加到您的 GameScene 类

class GameScene 

    // we need to make sure to set this when we create our GameScene
    var viewController: GameViewController!

在您的 GameViewController 文件中

// after GameScene is instantiated
gameScene.viewController = self

现在我们有了对 viewController 的引用,让我们在 GameScene 类中使用它

// somewhere in GameScene
self.viewController.gameOver()

【讨论】:

我试过了,但它仍然给出了类似的警告“...没有带有标识符 GameEnd 的 segue”,我不明白,因为我 100% 确定这是自定义 segue 的正确标识符.任何进一步的建议都会对我有很大帮助,但还是谢谢你 我知道两年多前有人问过这个问题,但是您能否更详细地描述一下 GameScene 是在哪里用您的 gameScene.viewController = self 行实例化的? @Rocket6488 GameScene 显示在 GameViewController 中。对我来说,我必须做一些额外的事情:if let gameScene = scene as? GameScene ... 并在 if 语句中放入 gameScene.viewController = self。希望这会有所帮助!【参考方案2】:

我已经通过创建协议完成了, 我有 3 个游戏场景(GameScene、GamePlayScene、GameEndScene)和一个游戏控制器(GameViewController)

首先创建游戏协议

protocol GameDelegate 
 func gameOver()

在 GameViewController 中实现协议

class GameViewController: UIViewController, GameDelegate 
override func viewDidLoad() 
 super.viewDidLoad()
 let scene = GameScene(size: skView.bounds.size)
        scene.scaleMode = .AspectFill
        scene.delegate = self
 

 // MARK: Game Delegate
 func gameOver() 
    self.performSegueWithIdentifier("yoursegue", sender: self)
 

将委托属性放在 GameScene 类中

class GameScene: SKScene 
 var delegate: GameDelegate?

 // call GamePlayScene and put delegate property
 func redirectToPlay() 
        let transition = SKTransition.pushWithDirection(SKTransitionDirection.Left, duration: 1.0)
        let menuScene = GamePlayScene(size: size)
         menuScene.delegate = self.delegate
        self.view?.presentScene(menuScene, transition: transition)
   

并将协议也放入 GamePlayScene 中

class GamePlayScene: SKScene 
     var delegate: GameDelegate?

     // call GameEndScene and put delegate property
     func gameScore() 
            let transition = SKTransition.pushWithDirection(SKTransitionDirection.Left, duration: 1.0)
            let menuScene = GameEndScene(size: size)
             menuScene.delegate = self.delegate
            self.view?.presentScene(menuScene, transition: transition)
       
    

最后,放置委托属性并调用gameOver函数

class GameEndScene: SKScene 
     var delegate: GameDelegate?

     init(size: CGSize) 
      // call gameOver function
      self.delegate?.gameOver()
     
   

希望能帮到你

真诚地, 唐尼

【讨论】:

【参考方案3】:

我不知道这是否仍然相关,但我想向您介绍这个问题的解决方案。

正如你在这里看到的Swift ios: Perform a Segue from an Instance in a ViewController to another ViewController 前段时间我遇到了完全相同的问题,我设法使用Protocols解决了这个问题。

问题是,您只能在 GameViewController 类中调用“performSegueWithIdentifier("GameOver", sender: nil)”,但您想从游戏场景中执行它。

因此,您可以在 GameScene 中创建这样的协议:

@objc protocol GameOverDelegate 
  func gameOverDelegateFunc()

以及游戏场景中委托的变量:

var gamescene_delegate : GameOverDelegate?

在您的 GameViewController 类中,您必须在类定义中添加委托

class GameViewController: UIViewController, GameOverDelegate 
...

并将 GameViewController 的 viewDidLoad 函数中的场景委托设置为 self:

scene.gamescene_delegate = self

最后一步是在你的 GameViewController 中实现 gameOverDelegateFunc() 函数:

func gameOverDelegateFunc() 
   self.performSegueWithIdentifier("GameOver", sender: nil)

这就是你所要做的。

当您想在 GameScene 中执行此 Segue 时,您只需通过委托调用该函数,如下所示:

gamescene_delegate?.gameOverDelegateFunc()

我希望一切都清楚,我可以提供帮助,

问候, 菲尔

【讨论】:

【参考方案4】:

我没有足够的代表来回复您的最后评论,但如果您仍然收到该错误,那是因为您尚未在 Interface Builder 中为该 segue 指定名称(或标识符)!

当您在 Interface Builder 中单击并拖动以在视图控制器之间绘制转场时,您可以通过出现在转场线中心的圆形图标来选择每个过渡,并为其指定一个“标识符”。然后,当您拨打performSegueWithIdentifier 时,它应该可以工作了!

这可能是圆形图标的样子,具体取决于 segue 的类型:

如果您对 segues 有点不确定,请查看 this tutorial 或 this one!

【讨论】:

以上是关于如何在 GameScene 中从 ViewController 调用方法的主要内容,如果未能解决你的问题,请参考以下文章

您如何存储 GameScene 以便我可以从 InGame 菜单转换回它?

从 SKSpriteNode 类实例访问 GameScene 中的数组?

在GameScene和ViewController Swift之间移动

在 GameScene 和 ViewController Swift 之间移动

如何更改启动时显示的默认 SKScene

如何捕捉 SKScene 暂停或 audioEngine 停止的时刻?