I'm having trouble trying to get the frame.width of GameScene into a custom class because I need the scene width for positioning nodes in my custom class init.
HudController.swift snippet
import SpriteKit
class HudController:SKNode {
var width:CGFloat
override init(){
width = GameScene().frame.width //I was hoping to add the scene width here
}
}
The following code crashes on me and I've tried heaps of other solutions with no success.
Can someone please help me with this issue?
Thanks!
UPDATED CODE ===
GameScene.swift
import SpriteKit
class GameScene: SKScene {
var hud = HudController(gameScene: self)
// set as global because I'm using it to also call hud functions in my game
}
HudController.swift
import SpriteKit
class HudController:SKNode {
var width:CGFloat
init(gameScene:SKScene){
width = gameScene.size.width
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
Every node in SpriteKit can retrieve the scene where it lives using the scene
property.
let node = SKNode()
node.scene
The scene
property returns a SKScene?
, the value is an optional because if the current node does not belong to a scene, of course there is not scene to retrieve.
Now, you could be tempted to use the self.scene
property inside the initializer of your HudController
.
class HudController: SKNode {
var width:CGFloat
override init() {
super.init() // error: property 'self.width' not initialized at super.init call
width = self.scene!.frame.width
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
But it will now work because you cannot invoke super.init
before having initialized the width
property.
Fine, then you could try this.
class HudController: SKNode {
var width:CGFloat
override init() {
width = self.scene!.frame.width // error: use of 'self' in property access 'scene' before super.init initializes self
super.init()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
Again compiler error because you are using self
before having called super.init()
.
And finally there is another problem, when the initializer is executed, the node it is being created has not a parent yet, so the self.scene
property does return nil
.
How to solve this?
First of all declare you initializer to receive a GameScene
.
class HudController: SKNode {
var width: CGFloat
init(gameScene:SKScene) {
width = gameScene.frame.width
super.init()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
Now, when you create this object (I hope you are doing it from the scene or from a node already added to the scene otherwise we are in trouble) you simply write
class Foo : SKNode {
func foo() {
guard let scene = self.scene else { return }
let controller = HudController(gameScene: scene)
}
}
On the other hand if you are creating HudController from you scene you simply write:
class MyScene : SKScene {
override func didMoveToView(view: SKView) {
super.didMoveToView(view)
let controller = HudController(gameScene: self)
}
}
That's it.
If you want an instance property of HudController inside your GameScene this is the code.
class HudController: SKNode {
var width: CGFloat
init(gameScene:SKScene) {
width = gameScene.frame.width
super.init() // <-- do not forget this
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
class GameScene: SKScene {
var hud : HudController?
override func didMoveToView(view: SKView) {
super.didMoveToView(view)
hud = HudController(gameScene: self)
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With