2
votes

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.

1
Try like this : if let gameScene = GameScene(fileNamed: "GameScene"){ } - Whirlwind
Now I get : "incorrect argument in call (have 'filename:', expected 'size:'). I'm pretty sure that there's something simple I'm missing... - Steve Ives
InitWithSize is not used when scene is loaded from .sks. I don't get why you have it in your GameScene? Remove it, and remove the implementation of init with coder and it will work. - Whirlwind
@Whirlwind - OK. I removed init(size: and init(code: and now I get an error from Xcode stating that "Class GameScene has no initialisers" - Steve Ives
Lol I haven't realized that your problem was similar to something I have already commented few times earlier, like in this question and I assumed that you were working on a scene subclass without any custom properties :) If that was the case, a default initializer would be called automatically and any other initializer implementation wouldn't be needed. Anyways, @Knight0fDragon gave the nice answer about initialization process, and like he said, you will get used to it after some time :) - Whirlwind

1 Answers

3
votes

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()
}