Reputation: 968
I'm building a PauseButton
class in my SpriteKit game, and I want to draw a label to the GameScene
when it is activated. However, I'm required to instantiate the button outside of didMoveToView
(right before it- in GameScene
) so that I can access it more "globally" from the touchBegan
method.
let pauseButton = PauseButton(theTexture: pauseButtonTexture,gameScene:GameScene)
override func didMoveToView(view: SKView) {
Ideally I would be able to pass in the view by instantiating it within didMoveToView
but as of now I don't know how to do this and also access it from the rest of the scene. That said, is there a way to pass in the current GameScene
instance I'm working with so that I can do something like gameScene.addchild(label)
from inside a method of my button class? I couldn't find anything useful on this, so any help would be great!
Upvotes: 0
Views: 463
Reputation: 10674
You basically can do it 2 ways.
1) Just create the property like this
var pauseButton: PauseButton!
and than instantiate it in didMoveToView like so.
override func didMoveToView(view: SKView) {
pauseButton = PauseButton(theTexture: pauseButtonTexture,gameScene: self)
addChild(pauseButton)
}
2) Use lazy instantiation so you can do what you tried to do initially.
A lazy var in in simplest form allows you to use self without doing step 1.
lazy var pauseButton: PauseButton = PauseButton(theTexture: pauseButtonTexture,gameScene: self)
override func didMoveToView(view: SKView) {
You could even do it like so to add more properties of this button all in the same spot.
lazy var pauseButton: PauseButton = {
let button = PauseButton(theTexture: pauseButtonTexture,gameScene: self)
button.zPosition = 200
button.position = CGPoint(x: self.frame.midX, y: self.frame.midY)
button.alpha = 0.5
return button
}()
override func didMoveToView(view: SKView) {
addChild(pauseButton)
}
Remember every SKNode/SKSpriteNode etc has a scene property. If your button class is a subclass of SKNode/SKSpriteNode than you can get its scene property and use the "as" operator to get a reference to GameScene without passing in the scene in the initialisation method.
e.g
class GameScene: SKScene {
lazy var pauseButton: PauseButton = PauseButton(theTexture: pauseButtonTexture,gameScene: self)
var someBool = false
override func didMoveToView(view: SKView) {
addChild(pauseButton)
pauseButton.loadPausedLabel()
}
func someMethod() {
}
}
class PauseButton: SKSpriteNode {
func loadPauseLabel() {
// Way 1, reference to current scene but not to specific class
guard let scene = scene else { return }
// Scene property is optional and is nil until button is added to a Scene so add the guard check.
scene.someBool = true // NOT WORKING
scene.someMethod() // NOT WORKING
let label = SKLabelNode(...
scene.addChild(label) // WORKING
// Way 2, use "as" to cast to specific scene (e.g GameScene) so you can call properties/methods on it. This is the same as passing GameScene in the init method.
guard let gameScene = scene as? GameScene else { return }
// Scene property is optional and is nil until button is added to a Scene so add the guard check.
// The button must be added to the scene you are trying the as? cast with, in this example GameScene.
gameScene.someBool = true // WORKING
gameScene.someMethod() // WORKING
let label = SKLabelNode(...
gameScene.addChild(label) // WORKING
}
}
As a tip, I would not add the pause label in the pauseButton subclass, I would add it from within the scene it self or from a pause menu subclass. Also I would not subclass each button, I would crate 1 class that can be used for all buttons in your game. You could create an enum with button names and pass that into the init method to distinguish between your buttons when they are pressed.
Your button subclass should only handle animations, textures etc. You can check out apples game DemoBots for an example.
Hope this helps
Upvotes: 2