Presenting a UIViewController from SKScene shows black screen
To present a SKScene
from another SKScene
you should do for example :
let nextScene = MainScene(size: self.scene!.size)
self.scene?.view?.presentScene(nextScene, transition: SKTransition.doorway(withDuration: 1))
You don't need to retrieve your currentViewController
because you have always access to the view
of your scene
As explained to the comments below, there are various methods to call a function implemented to your game viewController, one could be to create a delegate/protocol as showed in this code:
GameScene example:
import SpriteKit
protocol GameViewControllerDelegate: class {
func callMethod(inputProperty:String)
}
class GameScene: SKScene {
weak var gameViewControllerDelegate:GameViewControllerDelegate?
override func didMove(to view: SKView) {
gameViewControllerDelegate?.callMethod(inputProperty: "call game view controller method")
}
}
GameViewController example:
class GameViewController: UIViewController, GameViewControllerDelegate {
override func viewDidLoad() {
super.viewDidLoad()
if let view = self.view as! SKView? {
// Load the SKScene from 'GameScene.sks'
if let scene = SKScene(fileNamed: "GameScene") {
let gameScene = scene as! GameScene
gameScene.gameViewControllerDelegate = self
gameScene.scaleMode = .aspectFill
view.presentScene(gameScene)
}
view.ignoresSiblingOrder = true
view.showsFPS = true
view.showsNodeCount = true
}
}
func callMethod(inputProperty:String) {
print("inputProperty is: ",inputProperty)
}
}
Output:
New SKScene Set as Default in SpriteKit Game Turns Out Blank
If you have a corresponding SKS file created in the Scene editor then you load your scene like so...
// Load the SKScene from WelcomeScene.sks'
if let welcomeScene = WelcomeScene(fileNamed: "WelcomeScene") {
welcomeScene.scaleMode = .aspectFill
view.presentScene(welcomeScene)
}
if you do not have a corresponding SKS file created in the scene editor but would rather load the scene that was created in code use...
welcomeScene= WelcomeScene(size: skView.bounds.size)
welcomeScene.scaleMode = .aspectFill
skView.presentScene(welcomeScene)
Xcode 11.5 IOS 13.5 Dark screen after setting view controller in Scenedelgate
This line is wrong:
self.view?.window?.rootViewController = UINavigationController(rootViewController: HomeViewController())
The problem, in particular, is this phrase in your code:
HomeViewController()
That creates a new blank HomeViewController, not the instance you designed in the storyboard. To get that instance, tell the storyboard to instantiate it for you.
Presenting a UIViewController from an SKscene (SpriteKit)
You cannot move directly from an SKScene
to another UIViewController
.
However, the SKScene
is already contained in a UIViewController
.
You can use delegation
to pass a method call from the scene to its controller. The controller can then move to another view controller.
So...
Create a delegate protocol that contains a method something like...
- (void)transitionToOtherViewController;
Set the current view controller as the delegate of your scene.
self.scene.delegate = self;
When you want to move to another view controller. In the scene you would have something like...
[self.delegate transitionToOtherViewController];
Then in the view controller you have...
- (void)transitionToOtherViewController
{
MyOtherViewController *controller = [MyOtherViewController new];
[self.navigationController pushViewController:controller animated:YES];
}
Or something like this...
Losing reference to GameViewController from inside SpriteKit when moving between scenes - want to move between SKScene and UITableView
There are two simple methods to call a GameViewController
function from other classes: through a delegate
or by making the class instance static
.
// DELEGATE
//
// GameViewController.swift
protocol GameView_Delegate
{
func show_ui()
}
class GameViewController: UIViewController, GameView_Delegate
{
override func viewDidLoad()
{
// ...
if let view = self.view as! SKView?
{
if let scene = SKScene(fileNamed: "MenuScene")
{
scene.scaleMode = .aspectFill
// pass GameViewController reference
scene.gv_delegate = self
}
view.presentScene(scene)
}
// ...
}
func show_ui()
{
// show ui
// ...
}
}
// MenuScene.swift
class MenuScene: SKScene
{
var gv_delegate : GameView_Delegate!
func settings()
{
// call function show_ui from GameViewController
gv_delegate.show_ui()
}
func game_scene()
{
let transition = SKTransition.fade(with: UIColor.white, duration: 1.0)
let next_scene = GameScene()
next_scene.anchorPoint = CGPoint(x: 0.5, y: 0.5)
next_scene.scaleMode = self.scaleMode
next_scene.size = self.size
// before moving to next scene, we must pass the delegate, so we
// don't lose the connection with the GameViewController
next_scene.gv_delegate = gv_delegate
self.view?.presentScene(next_scene, transition: transition)
}
}
// GameScene.swift
class GameScene: SKScene
{
var gv_delegate : GameView_Delegate!
func settings()
{
// call function show_ui from GameViewController
gv_delegate.show_ui()
}
func main_scene()
{
let transition = SKTransition.fade(with: UIColor.white, duration: 1.0)
let next_scene = MainScene()
next_scene.anchorPoint = CGPoint(x: 0.5, y: 0.5)
next_scene.scaleMode = self.scaleMode
next_scene.size = self.size
// before moving to next scene, we must pass the delegate, so we
// don't lose the connection with the GameViewController
next_scene.gv_delegate = gv_delegate
self.view?.presentScene(next_scene, transition: transition)
}
}
When you enter a new scene, for example GameScene
, the old scene MainScene
in our case is deallocated (all variables emptied, all references destroyed) and a new GameScene
instance is created and displayed on screen. If afterwards you want to exit that scene and enter MainScene
, a new instance of that class will be created with the GameViewController
reference empty. We should reference it again or pass the reference before exiting the scene (as in my example).
// STATIC
//
// GameViewController.swift
class GameViewController: UIViewController
{
static var shared : GameViewController!
override func viewDidLoad()
{
super.viewDidLoad()
GameViewController.shared = self
// ...
}
func show_ui()
{
// show ui
// ...
}
}
// MenuScene.swift
class MenuScene: SKScene
{
func settings()
{
// call function show_ui from GameViewController
GameViewController.shared.show_ui()
}
}
Read pros/cons of each method and chose the one that suits your app the best. Also, avoid using UIKit inside SpriteKit.
Present another View Controller from SkScene
I assume by your question that you are looking to do some social media posting.
You can either pass a reference for your View Controller to your SKScene or you can use NSNotificationCenter
instead. I prefer to use the latter.
First make sure you have added the Social.framework to your project.
Import the social framework into your View Controller #import <Social/Social.h>
Then in your View Controller's viewDidLoad
method add this code:
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(createTweet:)
name:@"CreateTweet"
object:nil];
Next add this method to your View Controller:
-(void)createTweet:(NSNotification *)notification
{
NSDictionary *tweetData = [notification userInfo];
NSString *tweetText = (NSString *)[tweetData objectForKey:@"tweetText"];
NSLog(@"%@",tweetText);
// build your tweet, facebook, etc...
SLComposeViewController *mySLComposerSheet = [SLComposeViewController composeViewControllerForServiceType:SLServiceTypeTwitter];
[self presentViewController:mySLComposerSheet animated:YES completion:nil];
}
At the appropriate location in your SKScene, (won game, lost game, etc...) add this code:
NSString *tweetText = @"I just beat the last level.";
NSDictionary *userInfo = [NSDictionary dictionaryWithObject:tweetText forKey:@"tweetText"];
[[NSNotificationCenter defaultCenter] postNotificationName:@"CreateTweet" object:self userInfo:userInfo];
The above code sends a NSNotification, with text, which your View Controller will pick up and execute the specified method (which is createTweet in the above example).
Related Topics
Use of or Operator on Cloudkit Predicate
What Does This Mean? Variable Declared Followed by a Block Without Assignment
Swift - How to Set a Singleton to Nil
Differences Between Ways of Initializing a Dictionary
Swift: Ambiguous Reference to Member 'Map'
Stopping Timer at Defined Amount of Time in Swift
Custom Cell with Uitableview Inside Uicollectionviewcell
Secure Text .Echosbullets Not Working for Password Field
How to Change the Appearance of the Datepicker in the Swiftui Framework to Only Months and Years
Swift: Call Self Method Inside Init
How to Stop an Infinitely Rotating Image? and How Does One Implement Removeallanimations
Error While Using Property 'Cgrectgetwidth', It Says It Was Replaced with 'Cgrect.Width'
Swift Generics and Protocols Not Working on Uikit [Possible Bug]
Requestaccessformediatype Doesn't Ask for Permission
How to Display an Image by an API Url? Swift