Initialize a GameScene in Swift - Xcode 6.3 - ios

I am trying to initialize a scene in swift like so: let scene = GameScene(size: skView.bounds.size)
However the following error pops up in xcode:
Cannot invoke initializer for type 'GameScene' with an argument list of type '(size: CGSize)
Here is the related piece of code:
override func viewWillLayoutSubviews() {
var skView: SKView = self.view as! SKView
skView.showsFPS = true
skView.showsNodeCount = true
let scene = GameScene(size: skView.bounds.size)
scene.scaleMode = .AspectFill
skView.presentScene(scene)
}

You probably might want to include the following initializer within your GameScene
override init(size: CGSize) {
super.init(size: size)
}

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"
}

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

Problems with SpriteKit after upgrading to Swift 1.2

I've just upgraded to Swift 1.2 and I'm having trouble with my SpriteKit scene. My code below worked before the upgrade.
override func viewDidLoad() {
super.viewDidLoad()
// Configure the view.
let skView = self.view as! SKView
let scene:SKScene = GameScene.init(size: skView.bounds.size)
skView.ignoresSiblingOrder = true
scene.scaleMode = .AspectFill
skView.presentScene(scene)
}
The problem I'm having is with the line
let scene:SKScene = GameScene.init(size: skView.bounds.size)
The compiler complains that it expects a member name or constructor call after the type name. When I follow the compiler's instructions I get into a circle of further errors and complaints from the compiler. Any ideas?
I copied your code into my Swift 2.1 project and it runs fine.
class GameViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Configure the view.
let skView = self.view as! SKView
let scene:SKScene = GameScene.init(size: skView.bounds.size)
skView.ignoresSiblingOrder = true
scene.scaleMode = .AspectFill
skView.presentScene(scene)
}
override func prefersStatusBarHidden() -> Bool {
return true
}
}

Nothing is displaying in Simulator with viewWillLayoutSubviews

Within my GameView Controller.swift file, I removed viewDidLoad and put in viewWillLayoutSubviews because I will be using the dimensions of the device in my calculations. However, hello world SKLabelNode no longer is displayed in the simulator. Any ideas on what I'm doing wrong?
override func viewWillLayoutSubviews() {
super.viewWillLayoutSubviews()
let skView = self.view as SKView
if skView.scene != nil{
skView.showsFPS = true
skView.showsNodeCount = true
skView.showsPhysics = true
// Create and configure the scene
let scene = SKScene(size: skView.bounds.size)
scene.scaleMode = SKSceneScaleMode.AspectFill;
// Present Scene
skView.presentScene(scene)
}

Instance of a class and correct initialization

I've ported over this project - https://gist.github.com/cmezak/8393434 and have it working but I have a question about the differences in handling instances of a class and also initializing properly.
In GameScene.swift I have created a property with an instance to an SKSpriteNode like so:
class GameScene: SKScene {
var nodeToScroll: SKSpriteNode
init(size: CGSize) {
nodeToScroll = SKSpriteNode(imageNamed: "image")
super.init(size: size)
nodeToScroll.anchorPoint = CGPointMake(0, 0)
nodeToScroll.position = CGPointMake(0, size.height - nodeToScroll.size.height)
self.addChild(nodeToScroll)
}
}
And in GameViewController.swift I have:
var skView = SKView()
var scene = GameScene(size: CGSize())
var scrollView = UIScrollView()
class GameViewController: UIViewController, UIScrollViewDelegate {
override func viewDidLoad() {
super.viewDidLoad()
skView = SKView(frame: CGRectMake(0, 0, 1024, 768))
self.view.addView(skView)
scene = GameScene(size: skView.bounds.size)
scene.scaleMode = .AspectFill
scrollView = UIScrollView(frame: skView.frame)
scrollView.hidden = true
scrollView.delegate = self
self.view.addSubview(scrollView)
scrollView.contentSize = scene.calculateAccumulatedFrame().size
skView.addGestureRecognizer(scrollView.panGestureRecognizer)
skView.presentScene(scene)
}
Like I said, this is working but my attempts to follow Swift patterns such as
if let scene = GameScene.unarchiveFromFile("GameScene") as? GameScene {
it breaks. So my question is, how am I supposed to be handling cases where I need an instance of a scene outside of viewDidLoad? I thought this would be a simple port but now I've been staring at it so long I don't even know what I'm doing. Suggestions?
Edit:
I edited the viewController to this:
var skView: SKView!
var scene: GameScene!
var scrollView: UIScrollView!
class GameViewController: UIViewController, UIScrollViewDelegate {
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
self.view.addSubview(skView)
/* Set the scale mode to scale to fit the window */
scene.size = skView.bounds.size
scene.scaleMode = .AspectFill
scrollView = UIScrollView(frame: skView.frame)
scrollView.hidden = true
scrollView.delegate = self
self.view.addSubview(scrollView)
scrollView.contentSize = scene.calculateAccumulatedFrame().size
skView.addGestureRecognizer(scrollView.panGestureRecognizer)
skView.presentScene(scene)
}
}
I don't get any warnings or errors but when I run it I get "fatal error: use of unimplemented initializer 'init(coder:)' for class 'SwiftScrollKit.GameScene'"
So then I added
init(coder aDecoder: NSCoder!) {
super.init(coder: aDecoder)
}
to the GameScene class and now get 'Can't add self as subview' -- hooboy... I don't know why this is throwing me for such a loop but I just must not be grasping something here that is probably right under my nose.
You're going to be stuck until you get the scope of your instance variables corrected. In the gist you linked to, they're declared inside the #implementation { ... } block of your ViewController, but here they're declared outside the class completely, which means they're global in scope.
Inside viewDidLoad, you're redefining scene and skView in the scope of that method, hiding the global values while you do your configuration. These local variables then get deallocated at the end of viewDidLoad, so you've lost access to whatever you've set up there. (They may live on in the view hierarchy, but your global variables won't work.)
You'll want to move those global variables inside the class, and then access them using self.variableName so you don't mix them up with local variables. Other methods in the class will then also have access to what you've set up in viewDidLoad:
class GameViewController: UIViewController, UIScrollViewDelegate {
var skView: SKView!
var scene: GameScene!
var scrollView: UIScrollView!
override func viewDidLoad() {
super.viewDidLoad()
self.scene = // load the scene
self.skView = SKView(frame: CGRectMake(0.0, 0.0, 1024.0, 768.0))
self.view.addSubview(self.skView)
// etc
}
}
Finally, the "Can't add self as subview" error is happening because of this:
let skView = self.view as SKView
// ...
self.view.addSubview(skView)

Resources