How to call method from ViewController in GameScene
Asked Answered
M

4

9

I have a method that has a custom segue in my viewController that looks like this:

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

I call the method like so in GameScene.swift:

 GameViewController().gameOver()

I double checked the segue name and it is correct. Whenever I call this in my GameScene.swift file I get the SIGABRT message and I don't know why. I tried calling the function with only a println() message and it worked.

Any advice on why this is occurring and how I can successfully call the method in the GameScene.swift file would be greatly appreciated.

Thanks!

P.S. here is the crash log:

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

it says there is no segue id. with "GameEnd" but there is one and it works if used on the viewcontroller

Monomolecular answered 28/1, 2015 at 4:7 Comment(5)
Are you getting any crash report on debugger ?Reyesreykjavik
"terminating with uncaught exception of type NSException"Monomolecular
It's the usual message for issues with outlet connections etc.Monomolecular
please post the full log so that I can understandReyesreykjavik
I posted the crashlogMonomolecular
M
28

the reason this doesnt work is that you are creating a NEW instance of GameViewController and then you're calling gameOver on that. What you really want to do is reference your existing GameViewController

theres a few ways to do this, I'll give you one example.

add a viewController property to your GameScene class

class GameScene {

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

in your GameViewController file

// after GameScene is instantiated
gameScene.viewController = self

now we have a reference to viewController, lets use it in our GameScene class

// somewhere in GameScene
self.viewController.gameOver()
Meacham answered 28/1, 2015 at 7:46 Comment(3)
I tried this but it still gives a similar warning that "...has no segue with identifier GameEnd" which I do not understand since I am 100% sure that that is correct identifier for the custom segue. Any further advice would help me a lot, but thank you anywaysMonomolecular
I know this was asked a touch over two years ago, but Gould you please describe in a little more detail where GameScene is instantiated with your line for gameScene.viewController = self?Febrific
@Febrific GameScene is presented in the GameViewController. For me, I had to do a little extra: if let gameScene = scene as? GameScene { ... } and within that if statement put gameScene.viewController = self. Hope this helps!Wehner
M
6

I have done by create protocol, I have 3 game scene (GameScene, GamePlayScene, GameEndScene) and one game controller (GameViewController)

first create gameProtocol

protocol GameDelegate {
 func gameOver()
}

implement protocol in 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)
 }
}

put delegate property in GameScene class

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)
   }
}

and put protocol in GamePlayScene too

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)
       }
    }

and last, put delegate property and call gameOver function

class GameEndScene: SKScene {
     var delegate: GameDelegate?

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

Hope that work and can help you

Sincerely, Donny

Mcculloch answered 16/6, 2015 at 7:20 Comment(0)
N
1

I don't know if this is still relevant, but I would like to present you a solution to this problem.

As you can see here Swift iOS: Perform a Segue from an Instance in a ViewController to another ViewController I had the exact same problem some time ago, which I managed to fix using Protocols.

The problem is, that you can call the "performSegueWithIdentifier("GameOver", sender: nil)" only in your GameViewController Class, but you would like to execute it from your Gamescene.

Therefor you create in your GameScene a protocol like this:

@objc protocol GameOverDelegate {
  func gameOverDelegateFunc()
}

and a variable for the delegate in the Gamescene:

var gamescene_delegate : GameOverDelegate?

in your GameViewController Class you have to add the delegate in the class definition

class GameViewController: UIViewController, GameOverDelegate {
...
}

and set the delegate of the scene in the viewDidLoad function of your GameViewController to self:

scene.gamescene_delegate = self

The last step is to implement the gameOverDelegateFunc() function in your GameViewController:

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

This is all you have to do.

Whenever you want to perform this Segue in your GameScene you just have to call the function through the delegate like this:

gamescene_delegate?.gameOverDelegateFunc()

I hope that everything is clear and I could help,

Regards, Phil

Nix answered 28/5, 2015 at 21:31 Comment(0)
U
0

I don't have enough rep to reply to your last comment, but if you're still getting that error, that's because you haven't given that segue a name (or identifier) yet in Interface Builder!

When you click and drag to draw segues between view controllers in Interface Builder, you can select each transition by the circle icon that appears in the center of the segue lines and give it an 'identifier'. Then, when you call performSegueWithIdentifier, it should work!

This is what the circular icon might look like, depending on the type of segue:

Segue icon that lets you manage segue properties

If you're a little unsure of segues, check out this tutorial or this one!

Unfinished answered 10/2, 2015 at 0:47 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.