why isnt my second view loading after transition? - ios

I have two views, the initial one that works fine, and a second one that I am trying to display after I transition to it from a button on the first view.
However, when I click the button, the transition happens and the screen goes blank.
Below is the viewDidLoad inside of the UIViewController class for the second view.
Also when it hits the
let sKView = view as! SKVIEW
line it spits out
Could not cast value of type 'UIView' (0x10a313eb0) to 'SKView' (0x1094d5718).
(lldb)
How do I get it to display the view?
class PlayViewController: UIViewController {
var scene2: PlayScene!
override func viewDidLoad() {
super.viewDidLoad()
let skView = view as! SKView
skView.showsFPS = true
skView.showsNodeCount = true
scene2 = PlayScene(size: skView.bounds.size)
skView.ignoresSiblingOrder = true
/* Set the scale mode to scale to fit the window */
scene2.scaleMode = .AspectFill
skView.presentScene(scene2)
}
first class
class GameViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
if let scene = GameScene.unarchiveFromFile("GameScene") as? GameScene {
// 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)
}
}
the second scene
import SpriteKit
class PlayScene: SKScene {
override func didMoveToView(view: SKView) {
/* Setup your scene here */
let myLabel = SKLabelNode(fontNamed:"Chalkduster")
myLabel.text = "SCENE 2!";
myLabel.fontSize = 65;
myLabel.position = CGPoint(x:CGRectGetMidX(self.frame), y:CGRectGetMidY(self.frame));
self.addChild(myLabel)
}
override func touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent) {
/* Called when a touch begins */
for touch in (touches as! Set<UITouch>) {
let location = touch.locationInNode(self)
let sprite = SKSpriteNode(imageNamed:"Spaceship")
sprite.xScale = 0.5
sprite.yScale = 0.5
sprite.position = location
let action = SKAction.rotateByAngle(CGFloat(M_PI), duration:1)
sprite.runAction(SKAction.repeatActionForever(action))
self.addChild(sprite)
}
}
override func update(currentTime: CFTimeInterval) {
/* Called before each frame is rendered */
}
}

The issue is your view controllers view is your everyday run of the mill UIView instead of an SKView. Assuming you are using a storyboard click on the view controller and then click on the view and change the class to SKView instead of UIView.
Hopefully that helps.

I am not sure what are you trying to archive, you can try change your super class from UIViewController to SpriteViewController or you can create a new SKView and append to your view.
You cannot downcast a UIView to a SKView as a SKView inherit from UIView as you can see in the apple documentation
Inherits From
NSObject
UIResponder
UIView
SKView

Related

Swift 2 Game Main Menu

I am trying to implement a main menu to my Spritekit game, but whenever I try to present the scene I get a blank gray screen. Here is the code right now, which presents the game itself and not a menu:
class GameViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
if let scene = GameScene(fileNamed:"GameScene") {
let skView = self.view as! SKView
skView.showsFPS = true
skView.showsNodeCount = true
skView.showsDrawCount = true
skView.ignoresSiblingOrder = true
scene.scaleMode = SKSceneScaleMode.AspectFill
skView.presentScene(scene)
}
}
I'm new to this, and I wasn't sure what to do so I tried replacing GameScene with the menu scene, which gave me the gray screen. Any help will be appreciated.
Use this code to load a SKScene file that is created in code only and not in the Scene editor
override func viewWillLayoutSubviews() {
super.viewWillLayoutSubviews()
if let skView = self.view as? SKView {
if skView.scene == nil {
let scene = MenuScene(size: skView.bounds.size)
skView.showsFPS = false
skView.showsNodeCount = true
skView.showsPhysics = true
skView.ignoresSiblingOrder = true
scene.scaleMode = .aspectFill
skView.presentScene(scene)
}
}
}
and then in your MenuScene file you will need an init func
init(size: CGSize) {
super.init(size: size)
name = "menuScene"
}

GameViewController to GameScene using presentScene with SKTransition

Tried to perform an SKTransition for the very first loading of GameScene from GameViewController but nothing seemed to happen. Can't we perform some transition while presenting a scene directly from the GameViewController? It seemed to me quite hilarious that the normal present scene is working but not the one with transition. Here is the code :
class GameViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
if let view = self.view as! SKView? {
let scene = GameScene(size: view.bounds.size)
// Set the scale mode to scale to fit the window
scene.scaleMode = .aspectFill
//transition
let transition = SKTransition.doorsOpenVertical(withDuration: 2)
// Present the scene
view.presentScene(scene, transition: transition)
view.ignoresSiblingOrder = true
view.showsFPS = true
view.showsNodeCount = true
}
}
}
class GameScene: SKScene {
override func didMove(to view: SKView) {
self.backgroundColor = SKColor.red
}
}
Please solve the query.

Swift, SpriteKit: Deallocate a Gamescene et reallocate a new one

I need to deallocate gamescene after the player have finished a level so that the memory is available to load another level of my game. If I don't do that, I have a crash of my app because of memory issues.
I have followed the indications given there:
Swift: Deallocate GameScene after transition to new scene?
But unfortunately, it doesn't work for me. I get an error "Could not cast value 'UIView' to 'SKView' in my GameViewController class. Here is my whole code:
import Foundation
import UIKit
import SpriteKit
class GameViewController: UIViewController {
var scene1: SKScene?
var scene2: SKScene?
var scene3: SKScene?
var skView: SKView?
func nextSceneAction1() {
scene2 = nil
scene3 = nil
skView! = self.view as! SKView
skView!.showsFPS = true
skView!.showsNodeCount = true
/* Sprite Kit applies additional optimizations to improve rendering performance */
skView!.ignoresSiblingOrder = true
scene1 = TransitionSigns(size: skView!.frame.size)
scene1!.size.width = 2048
scene1!.size.height = 1536
/* Set the scale mode to scale to fit the window */
scene1!.scaleMode = .AspectFill
let transition = SKTransition.revealWithDirection(.Right, duration: 2)
scene1!.scaleMode = .AspectFill
skView!.presentScene(scene1!, transition: transition)
}
func nextSceneAction2() {
scene1 = nil
scene3 = nil
let skView = self.view as! SKView
skView.showsFPS = true
skView.showsNodeCount = true
/* Sprite Kit applies additional optimizations to improve rendering performance */
skView.ignoresSiblingOrder = true
scene2 = TransitionSigns(size: skView.frame.size)
scene2!.size.width = 2048
scene2!.size.height = 1536
/* Set the scale mode to scale to fit the window */
scene2!.scaleMode = .AspectFill
let transition = SKTransition.revealWithDirection(.Right, duration: 2)
scene2!.scaleMode = .AspectFill
skView.presentScene(scene2!, transition: transition)
}
func nextSceneAction3() {
scene1 = nil
scene2 = nil
let skView = self.view as! SKView
skView.showsFPS = true
skView.showsNodeCount = true
/* Sprite Kit applies additional optimizations to improve rendering performance */
skView.ignoresSiblingOrder = true
scene3 = TransitionSigns(size: skView.frame.size)
scene3!.size.width = 2048
scene3!.size.height = 1536
/* Set the scale mode to scale to fit the window */
scene3!.scaleMode = .AspectFill
let transition = SKTransition.revealWithDirection(.Right, duration: 2)
scene3!.scaleMode = .AspectFill
skView.presentScene(scene3!, transition: transition)
}
override func viewWillLayoutSubviews() {
// 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
let scene = MainView(size: skView.frame.size)
scene.size.width = 2048
scene.size.height = 1536
/* Set the scale mode to scale to fit the window */
scene.scaleMode = .AspectFill
skView.presentScene(scene)
}
override func shouldAutorotate() -> Bool {
return true
}
override func supportedInterfaceOrientations() -> UIInterfaceOrientationMask {
if UIDevice.currentDevice().userInterfaceIdiom == .Phone {
return UIInterfaceOrientationMask.AllButUpsideDown
} else {
return UIInterfaceOrientationMask.All
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Release any cached data, images, etc that aren't in use.
}
override func prefersStatusBarHidden() -> Bool {
return true
}
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewDidDisappear(animated: Bool) {
self.view.removeFromSuperview()
}
override func viewWillDisappear(animated: Bool){
self.view.removeFromSuperview()
}
}
I call the different functions nextSceneAction1(), nextSceneAction2(), and nextSceneAction3() from my other classes with:
let controller1 = GameViewController()
controller1.nextSceneAction1()
or
let controller2 = GameViewController()
controller2.nextSceneAction1()
When the new scene is loaded, I get this error: "Could not cast value of type 'UIView' to 'SKView'. Do you know what is wrong with this code?
By the way, I'm open with all other possibilities to clean old scene from memory before loading a new one so that there is no memory crash during the life of the app.
In general a SKScene automatically deallocates once you transition to a new scene, unless you have a memory leak, so usually you don't have to do anything in particular to free memory.
To see if your scene has deallocated you can add the deinit method
func deinit {
print("scene did deallocate")
}
If this method gets called when you change scenes you know everything correctly deallocated, if it doesn't get called you have a memory leak.
Also you code is faulty, you are creating a new GameViewController instance everytime you change scene instead of accessing the current instance.
let controller2 = GameViewController() // creates new instance of GameViewController
controller2.nextSceneAction1()
You normally only load your 1st scene from your GameViewController and than all other scene changes can be done directly in the SKScene you are in. Don't bother using the GameViewController for this.
In your current SKScene you can change to a new scene like this (e.g from GameScene to MenuScene)
class GameScene: SKScene {
...
func loadMenuScene() {
let menuScene = MenuScene(size: self.size) // use size of current scene
let transition = Some SKTransition
view?.presentScene(menuScene, withTransition: transition)
}
}
Hope this helps

(Swift SpriteKit) Only allow SKScene to present once

This code resides in the viewDidLoad function. The first time it is called it is fine. But then I present a subView on top of it from the same storyboard file and when 'let skView = gameView as! SKView' gets called again and throws a Fatal error: Found nil... How do I stop it from being called the other times? I can't think of any checks I could but in place.
if let scene = GameScene(fileNamed:"GameScene") {
// Configure the view.
let skView = gameView 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)
}
override func viewWillLayoutSubviews() {
super.viewWillLayoutSubviews()
let skView = self.view as! SKView
if skView.scene == nil {
if let scene = GameScene(fileNamed:"GameScene") {
skView.presentScene(scene)
}
}
}

Need help instantiating a controller and storyboard scene from controller SWIFT?

I have a controller that is using a Singleton to change SKScenes in a single storyboard scene.
class GameViewController: UIViewController, GKGameCenterControllerDelegate, GADBannerViewDelegate, GADInterstitialDelegate, ADBannerViewDelegate, FBLoginViewDelegate, CLLocationManagerDelegate, MapViewControllerDelegate {
var sharedInstance = Singleton.sharedInstance
var skView:SKView!
var scene:GameScene! = GameScene.unarchiveFromFile("GameScene") as? GameScene
var searchedTypes = ["bakery", "bar", "cafe", "grocery_or_supermarket", "restaurant"]
let locationManager = CLLocationManager()
var adHelper: AdHelper = AdHelper()
override func viewDidLoad() {
super.viewDidLoad()
locationManager.delegate = self
locationManager.requestWhenInUseAuthorization()
// Configure the view.
skView = self.view as SKView
skView.showsFPS = false
skView.showsNodeCount = false
/* 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, transition: SKTransition.crossFadeWithDuration(kSceneTransitionSpeed))
}
// LOAD MAP SCENE
func showMap(){
let viewController:UIViewController = UIStoryboard(name: "Main", bundle: nil).instantiateViewControllerWithIdentifier("MapController") as UIViewController
self.presentViewController(viewController, animated: false, completion: nil)
}
}
In my game scene I have a button that I am calling to this controller to change to the other scene in the storyboard because I don't have a layout button to use an IBAction
import SpriteKit
class GameScene: SKScene {
var sharedInstance = Singleton.sharedInstance
let playButton = Button(imageNamed:"playButton");
let highscoresButton = Button(imageNamed:"highscoresButton");
let creditsButton = Button(imageNamed:"creditsButton");
let moreGamesButton = Button(imageNamed: "moreGamesButton")
override func didMoveToView(view: SKView) {
// background
let background = SKSpriteNode(imageNamed: "background")
background.position = CGPointMake(self.size.width/2, self.size.height/2)
self.addChild(background)
// main image
let main = SKSpriteNode(imageNamed: "main")
main.position = CGPointMake(self.size.width/2, self.size.height/2)
self.addChild(main)
// buttons
moreGamesButton.position = CGPointMake(self.size.width/2 + playButton.size.width, main.position.y + main.size.height/2 + playButton.size.height)
self.sharedInstance.addChildFadeIn(moreGamesButton, target: self)
}
override func touchesBegan(touches: NSSet, withEvent event: UIEvent) {
for touch: AnyObject in touches {
let location = touch.locationInNode(self);
if self.nodeAtPoint(location) == self.moreGamesButton {
var gameController: GameViewController=GameViewController()
gameController.showMap()
}
}
}
override func update(currentTime: CFTimeInterval) {
/* Called before each frame is rendered */
}
}
When I click this I don't get a defined error just hits a break and it the thread I get "Swift dynamic cast failed".
Can I not call the controller like that within my scene or is is it a problem in instantiating the other controller?

Resources