I have a app that Im making and I need to transition from my single view application view to a GameScene. I added the GameViewController.swift, GameScene.swift and the GameScene.sks to my project. How do I segue from my view controller to my GameScene? Ive looked up examples but none of them help, any quick solutions would be great.
Here is the code Im using to go to my game.
let storyboard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let gameView: UINavigationController = storyboard.instantiateViewController(withIdentifier: "miniGame") as! UINavigationController
self.present(gameView, animated: true, completion: nil)
but I get an error
Could not cast value of type 'UIView' (0x2d73b00) to 'SKView' (0x1ba878c).
(lldb)
it pops the error on this line of code in my GameViewController
if let view = self.view as! SKView? {
you have to select your view in ViewController then in identity inspector set it's custom class to "SKView".
it will solve your problem.
The following should work for you.
import UIKit
import SpriteKit
class GameViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
if let scene = GameScene(fileNamed:"GameScene.sks") {
// Configure the view.
let skView = self.view as! SKView
skView.showsFPS = true
skView.showsNodeCount = true
/* Sprite Kit applies additional optimizations to improve rendering performance */
skView.ignoresSiblingOrder = false
/* Set the scale mode to scale to fit the window */
scene.scaleMode = .AspectFill
skView.presentScene(scene)
}
}
}
Make sure (1) that you have GameViewController set to the class name of the view controller scene over the Main.storyboard, (2) that you have SKView set to the class name of View under Game View Controller
Related
I am new to SpriteKit and see the code like let skView = view as! SKView so what is use of this? Also I am confused about the difference between view and skView, scene and GameScene?
class GameViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let scene = GameScene(size: view.bounds.size)
let skView = view as! SKView
skView.showsFPS = true
skView.showsNodeCount = true
skView.ignoresSiblingOrder = true
scene.scaleMode = .resizeFill
skView.presentScene(scene)
}
override var prefersStatusBarHidden: Bool {
return true
}
}
as! means "force cast". The value of view will be casted as SKView. If this fails, because view is nil or of a different type, the code will crash. That's why you should avoid using as! when you are not 100% sure of what type the value is.
Related:
https://stackoverflow.com/a/36024775/4687348
Type Casting - The Swift Programming Language
SKView is a subclass of UIView that has additional capabilities for SpriteKit functionality. The as! operator is downcasting the view of UIView to a SKView, to enable using SKView specific functionality in viewDidLoad().
Generally, the as? operator is recommended because it will gracefully fail to nil if it doesn't succeed, whereas as! will crash the app if the casting is unsuccessful. If you are 100% certain that you will always have the view is of type SKView in this case, then using as! can be an appropriate and less verbose choice.
For more information, I recommend reading this Stackoverflow post that compares the use of as, as?, and as!.
QUESTION: How can I dismiss a ViewController from my GameScene.swift ?
SITUTATION: I have 2 VCs in my SpriteKit Game, like so:
ViewController.swift ----Press Play-----> GameViewController
When the player loses, I want to dismiss the GameViewController so the player can press play again. I check for the player's loss in my GameScene.swift and would like to dismiss the GameVC from there.
N.B.: Googled this without success.
WHAT I TRIED:
1) Creating a gameVC instance in my GameScene.swift and dismissing it like so:
let gameVC = GameViewController()
gameVC.dismissViewController(false,completion: nil)
2) Doing:
self.view.window!.rootViewController?.dismissViewControllerAnimated(false, completion: nil)
Those don't work for obvious reasons ^^
You don't want to "grab" the existing instance: https://pragprog.com/articles/tell-dont-ask
You need to either hand GameScene a reference to the view controller so it can dismiss it, or use the delegate pattern to communicate backwards to a controlling object that the VC should be dismissed/dismiss itself.
A simple example… you can add a GameViewController property to GameScene, then dismiss the VC at the appropriate time:
class GameScene: SKScene {
var gameVC: GameViewController?
func gameDidEnd() {
gameVC?.dismissViewControllerAnimated(true) {
// if desired, do any cleanup after the VC is dismissed
}
}
}
Then, just set this property when creating the GameScene object in the first place:
if let gameScene = GameScene(fileNamed: "MyScene") {
gameScene.gameVC = someGameVC
}
This simple approach will tightly couple GameScene and GameViewController, making it a bit more difficult if you ever want to use one of these objects without the other. But for this simple use case, it may be fine.
I've follow some of your discussion. I want to add some code, because usually I prefeer to work with one ViewController or two and many SKScene and SKNode, but in this case could be useful to have a currentViewController reference:
class MyModelScene: SKScene {
let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
var currentViewController : MyModelViewController! = MyModelViewController()
// MyModelViewController is a customized UIViewController
override func didMoveToView(view: SKView) {
super.didMoveToView(view)
print("---")
print("∙ \(NSStringFromClass(self.dynamicType))")
print("---")
}
}
class Level1Scene: MyModelScene {
...
}
In the UIViewController:
class PreloadViewController: MyModelViewController {
override func viewDidLoad() {
super.viewDidLoad()
if let scene = Level1Scene(fileNamed:"Level1Scene") {
// Configure the view.
let skView = self.view as! SKView
skView.showsFPS = true
skView.showsPhysics = true
skView.showsNodeCount = true
skView.ignoresSiblingOrder = true
/* Set the scale mode to scale to fit the window */
scene.scaleMode = .ResizeFill
scene.currentViewController = self
skView.presentScene(scene)
}
}
}
With this code , you've always a currentViewController reference in your SKScene and you can check if it's the correct viewController you want to dismiss or not.
I created a new Swift file called GamePlayController.swift and I hooked it up to one of my Views in Storyboard. I am trying to run this code, but I get a SIGABRT at the line with the double asterisks. What is the reason for this?
import UIKit
import SpriteKit
class GamePlayController: UIViewController, UIGestureRecognizerDelegate {
var scene: GameScene!
override func viewDidLoad() {
super.viewDidLoad()
// Configure the view.
**let skView = view as! SKView**
skView.multipleTouchEnabled = false
// Create and configure the scene.
scene = GameScene(size: skView.bounds.size)
scene.scaleMode = .AspectFill
// Present the scene.
skView.presentScene(scene)
}
view in this case is not an SKView instance. Try making an outlet in your source file to the SKView in the view controller in your storyboard. Google "iOS create storyboard outlet" if you're not sure how.
Hi I have a spriteKit game set up where everytime the user dies Ill get a pop up ViewController with Try again button and some iAds set up.
I have a segue to the viewController and an unwind segue from the VC to the gameViewController.
When I call the unwind func I reinitialize the scene for different reasons. My question is, am I creating view over view which will eventually lead to a crash or am I correctly reinitializing the scene. I took the code from viewDidLoad and put it into a function called "setUp()" and I call that function from the unwindSegue.
check it out: (all in GameViewController)
var currentLevel: Int!
var gameScene = GameScene()
override func viewDidLoad() {
super.viewDidLoad()
currentLevel = gameScene.currentLevel
setUp()
}
#IBAction func perpareForUnwind(unwindSegue: UIStoryboardSegue) {
setUp()
}
func setUp() {
if let scene = GameScene.level(currentLevel) {
// Configure the view.
let skView = self.view as SKView
skView.showsFPS = true
skView.showsNodeCount = true
/* Sprite Kit applies additional optimizations to improve rendering performance */
skView.ignoresSiblingOrder = true
/* Set the scale mode to scale to fit the window */
scene.scaleMode = .AspectFill
skView.presentScene(scene)
scene.viewController = self
}
}
You are not creating a new view controller if you are using the unwind segue correctly. From what it looks like that is the case. If you are still not confident you can log out println(\(self)) and make sure of it (My swift is rusty but I think that is how you log it out).
Your question title asks about view controllers but your question info asks about creating additional views. This isn't an issue either. When you do
let skView = self.view as SKView
You are getting the current view of the view controller and just casting it as an SKView. You are not recreating another view at all.
Hopefully that helps.
Inside my main UIViewController, I'm defining two SKScenes. I want to present only gameScene at first, and then present uiScene later, triggered by an action in gameScene (hitting the pause button).
The problem is that skView, the view containing both scenes, is not recognized outside of the UIViewController.
The code is below. Any help would be appreciated.
class GameViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let skView = view as SKView
let gameScene = GameScene(size: view.bounds.size)
gameScene.scaleMode = .ResizeFill
skView.presentScene(gameScene)
let uiScene = UIScene(size: view.bounds.size)
uiScene.scaleMode = .ResizeFill
uiScene.backgroundColor = UIColor.clearColor()
//skView.presentScene(uiScene) // I want to present this line from within gameScene.
}
}
let reveal = SKTransition.flipHorizontalWithDuration(0.5)
let scene = uiScene(size: size)
self.view?.presentScene(scene, transition:reveal)
You can transition from one scene to another from within the scene. My code is pulled from http://www.raywenderlich.com/84434/sprite-kit-swift-tutorial-beginners in the last section.
Remember to import the header of the scene you are transitioning TO in the scene you are transitioning FROM.