Steve Ives Steve Ives - 2 months ago 16
iOS Question

How to add an .sks files to existing Swift/Sprite-Kit project?

I started following Ray Wenderlich's 'Space Invaders' tutorial, but have diverged considerably. I now have 3 SKScenes - my title screen, my main game screen and my end level/game over screen. The title screen and the end game scene I added and these both have .sks files; the main game screen does not and all elements (SKSpriteNodes etc) are placed programatically. The flow of my program is as follows:

enter image description here

I now would actually like to place some events of the main game screen via the scene editor, so I created a .sks file for it and tried to change my titleScene.swift as follows:

from:

let gameScene = GameScene(size:CGSize(width: 1536, height: 2048))


to:

let gameScene = SKScene(fileNamed: "GameScene.sks") as! GameScene!


However, this then gives:

enter image description here

I tried to remove the
required init(coder aDecoder: NSCoder)
but Xcode then complains that


required init(coder: must be supplied by subclass of SKScene


However my
titleScene
and
gameOverScene
are also sub-classes of SKScene and they don't have init(coder:)

I really can't see the difference in what I'm doing to display my titleScreen and my gameOverScene via (fileNames:) and their .sks file and trying to do the same for my gameScene.

Answer

The reason why you are getting the required is because you have variables that are not optional or not initialized before init takes place.

If you have variables that need to be assigned inside of an init function, then you would do:

required init?(coder aDecoder: NSCoder)
{
   super.init(coder: aDecoder)
}

But then you will ask me: Mr Knight0fDragon, it is telling me to replace fileNamed with coder, and it is not compiling when I switch it.

Well this is because init(fileNamed:) is a convenience init, not a designated init. In order to be able to subclass a class and get all of it's convenience inits, you need to override all of it's designated inits.

Now with SKScene, you have 3, and you already know about 1.

Let's override the other 2:

override init() {
    super.init()
}
override init(size: CGSize) {
    super.init(size: size)
}

Alright, now this puppy should be ready to compile, we just need to get the variables assigned.

Well what I like to do is create a setup method for any variable that has to be assigned in any version of initialization after the super is called.

Unfortunately we can't do this for constants before super is called, so those we would need to set up in each method. The reason being is that self does not fully exist yet.

This would end up looking like this:

let constant : String
required init?(coder aDecoder: NSCoder)
{
   constant = "hi"
   super.init(coder: aDecoder)
   setup()
} 
override init() {
    constant = "hi"
    super.init()
    setup()
}
override init(size: CGSize) {
    constant = "hi"
    super.init(size: size)
    setup()
}