I'm having a hard time finding the answer to this question I assume is not that hard.
How can I reference methods and properties defined on a viewcontroller from a SKScene ?
And building on that: How can you reference the ViewController from a SKScene that was loaded from within another SKScene?
Thanks for your NSNotification method for exiting a sprite kit scene back to the calling view controller. This is a simple way to jump back to UIKit & will post my code. I'm working is swift & just added 4 lines of code for those working in Swift. This code was added to the view controller in the viewDidLoad function.
I added this code to my touchesBegan function in my SKscene to get back to the view controller
Now when I hit the "quit" labelNode, it will let me run a function called quitToLevel in the view controller that presented my scene. This function pops me back to my main screen since I'm using a navigation controller but could be used for any purpose.
I tried several other methods of exiting a scene, but had issues if I was jumping around in multiple scenes of loosing the reference back to the view controller. I can use this method from any scene
This isn't the most elegant solution, but how about a "back reference" from your SKScene subclass to the GameViewController? Something like this:
Your SKScene subclass looks like this:
and later:
SKNode and its subclasses already have a
.parent
and a.scene
property, so it's not like this approach is unheard of. Yeah, we're hard-coding a dependency and more tightly coupling our code, but we're writing less code, so it can't be all bad.You should avoid to reference
UIViewController
fromSKScene
, because it breaks MVC pattern.As an alternative way you can use
NSNotificationCenter
to notifyUIViewController
about high score:In
ViewController
:In
SKScene
:in theory you should not do that but in practice...
A better option than my "back reference" answer is to use a protocol to explicitly define the methods that a
SKScene
subclass expects theUIViewController
subclass to implement. Here are the steps you'll need to go through.1) Define the protocol (contract) that the
UIViewController
will need to adopt and conform to:2) The
UIViewController
subclass now adopts the protocol:class GameViewController: UIViewController,GameManager{
3) The
GameScene
gets an ivar that references theUIViewController
:var gameManager:GameManager?
4) When the
GameManager
needs to call theUIViewController
, it does so like this:gameManager.loadHighScoreScene()
We now have a well-defined contract of what a
GameManager
is. Any other developers (and the current developer's future self) that work on this project now know which methods aGameManager
should implement. This means we could easily port this code to a different project (and thus a differentUIViewController
) and it would still work as long as this newUIViewController
adopted theGameManager
protocol.Similarly, if we decided to move our scene navigation code out of the view controller, and instead placed it in a singleton class, this singleton class would merely need to adopt the
GameManager
protocol.Which approach to use?
This thread gives 4 approaches to solving the problem, and I have personally used all 4. Here's my take on them:
1) Hard-coding a call to the
UIViewController
subclass:(self.view!.window!.rootViewController as! GameViewController).loadGameScene(1)
Advantage: 1 line of code!
Disadvantage: A very tight coupling of 2 classes, without an explicit contract.
2) Using a pointer back to the
UIViewController
:Advantages: Very little code required, No protocol required.
Disadvantages: Tight coupling of 2 classes. No explicit contract.
3) Using
NSNotificationCenter
:Advantage: Loosely coupled classes.
Disadvantages: more code needed to set up the broadcaster, receiver, and callback methods. Harder to trace and debug the code. No explicit contract. The "one-to many" capability of notifications is nice, but doesn't help us here.
4) Creating a protocol:
Advantages: An explicit contract. The gods of MVC will be pleased.
Disadvantage: More code to write (but much less than notifications).