How do I go from SKScene to UIViewController by code?
You cannot present a viewController from within a SKScene as it is actually only being rendered on a SKView. You need a way to send a message to the SKView's viewController, which in turn will present the viewController. For this, you can use delegation or NSNotificationCenter.
Delegation
Add the following protocol definition to your SKScene's .h file:
@protocol sceneDelegate <NSObject>
-(void)showDifferentView;
@end
And declare a delegate property in the interface:
@property (weak, nonatomic) id <sceneDelegate> delegate;
Then, at the point where you want to present the share screen, use this line:
[self.delegate showDifferentView];
Now, in your viewController's .h file, implement the protocol:
@interface ViewController : UIViewController <sceneDelegate>
And, in your .m file, add the following line before you present the scene:
scene.delegate = self;
Then add the following method there:
-(void)showDifferentView
{
[self performSegueWithIdentifier:@"whateverIdentifier"];
}
NSNotificationCenter
Keep the -showDifferentView method as described in the previous alternative.
Add the viewController as a listener to the notification in it's -viewDidLoad method:
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(showDifferentView) name:@"showDifferenView" object:nil];
Then, in the scene at the point where you want to show this viewController, use this line:
[[NSNotificationCenter defaultCenter] postNotificationName:@"showDifferentView" object:nil];
Getting the UIViewController from an SKScene
Your view controller is:
self.view?.window?.rootViewController
Example:
let isReady = GADRewardBasedVideoAd.sharedInstance().isReady
guard let controller = self.view?.window?.rootViewController as? GameViewController else {return}
if isReady {
print("ADMOB: started")
GADRewardBasedVideoAd.sharedInstance().present(fromRootViewController: controller)
}
How to get back from SKScene to UIViewController (MenuVC)?
try:
self.view.window!.rootViewController?.dismiss(animated: false, completion: nil)
This should dismiss all views above the rootViewController
edit:
This may work for you as we define the ViewController, make sure in your Storyboard your MenuVC
has an Identifier:
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let vc = storyboard.instantiateViewController(withIdentifier: "MenuVC") // Make sure is the same identifier as in the storyboard.
vc.view.frame = (self.view?.frame)!
vc.view.layoutIfNeeded()
UIView.transition(with: self.view!, duration: 0.3, options: .transitionFlipFromRight, animations:
{
self.view?.window?.rootViewController = vc
}, completion: { completed in
})
}
Edit:
It seems the best way to do this, is to host your SKScene class in another view controller. What I suggest is to create another ViewController where your SKScene will be, for example SKViewController
. Embed your MenuVC
inside a navigationController
clicking on it in storyBoard, clicking Editor (from the menu at the top) > Embed in > Navigation Controller. Edit your MenuVC so that instead of opening your Scene, you just segue to the SKViewController, and open the scene there. To do this just create a segue from MenuVC
in storyboard, with an identifier "MenuToSKScene" for example, and when you want to open the scene, from your MenuVC just do:
self.performsegue(with identifier: "MenuToSKScene", sender: self)
Then do whatever you do currently in MenuVC
in SKViewController
instead to open the scene.
This will send you to the SKViewController, which has your SKScene class. Then when you want to go back to the menu, all you have to do is:
self.dismiss(animated: true, completion: nil)
or create a segue from SKViewController to MenuVC with identifier "SKSceneToMenu" and call:
self.performsegue(with identifier: "SKSceneToMenu", sender: self)
So essentially, don't open the SKScene
from MenuVC
, but have a separate viewController SKViewController
that you open when you want to open your scene, so that you can jump back to the menu easily.
Moving from SKScene to ViewController
Replace the code related to currentViewController
with this:
self.view?.window?.rootViewController?.present(viewController, animated: true, completion: nil)
It should work.
You can also create a segue
in Storyboard
and call it like this:
self.view?.window?.rootViewController?.performSegue(withIdentifier: "VC", sender: self)
EDIT:
I've tried on one of my app now the next solution and it worked:
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let vc = storyboard.instantiateViewController(withIdentifier: "VC")
vc.view.frame = rootViewController.view.frame
vc.view.layoutIfNeeded()
UIView.transition(with: window, duration: 0.3, options: .transitionFlipFromRight, animations:
{
window.rootViewController = vc
}, completion: { completed in
// maybe do something here
})
To me it worked, I hope it will solve your case :)
Segue in SKScene to UIViewController
You are calling the segue on the root viewController. I think that is the problem. You need to call the segue on the scene's viewController instead (where I am assuming you have created the segue, hence it is not being found on the root viewController).
Now the problem is that an SKScene does not have direct access to it's viewController, but just the view in which it is contained. You need to create a pointer to it manually. This can be done by creating a property for the SKScene:
class GameScene: SKScene {
weak var viewController: UIViewController?
...
}
Then, in the viewController class, just before skView.presentScene(scene)
scene.viewController = self
Now, you can access the viewController directly. Simply call the segue on this viewController:
func returnToMainMenu(){
viewController?.performSegueWithIdentifier("menu", sender: vc)
}
Related Topics
Programmatically Switching Between Tabs Within Swift
Cannot Set Searchbar as Firstresponder
Popover in Swift 3 on iPhone iOS
Linker Error in iOS (Duplicate Symbols for Architecture X86_64)
How to Set Device (Ui) Orientation Programmatically
Decimal to Fraction Conversion in Swift
Could Not Load the "" Image Referenced from a Nib in the Bundle with Identifier
Swiftui: What Is @Appstorage Property Wrapper
Keyboard and Cursor Show, But I Can't Type Inside Uitextfields and Uitextviews
Expand Uilabel Inside Uitableview with "More" Button Like Instagram
Module Compiled with Swift 4.2.1 Cannot Be Imported by the Swift 5.0 Compiler
Uicollectionview - Diddeselectitematindexpath Not Called If Cell Is Selected
How to Get Only Images in the Camera Roll Using Photos Framework
Right Way of Determining Internet Speed in iOS 8
Swiftui - iOS 13 Uiviewrepresentable of Wkwebview Gets Thread 1: Exc_Breakpoint Crash