How to call method from ViewController in GameScene

12,756

Solution 1

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

Solution 2

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

Solution 3

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

Share:
12,756
Jonathan H.
Author by

Jonathan H.

Updated on July 21, 2022

Comments

  • Jonathan H.
    Jonathan H. almost 2 years

    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