SwiftiSwift
SwiftiSwift

Reputation: 8757

How can I access a changed property in a different class in SpriteKit

I have a function(touchesBegan) in a class which changes a property.

class Difficulty: SKScene {
    var easy: SKSpriteNode?
    var middle: SKSpriteNode?
    var hard: SKSpriteNode?
    var difficultLevel: DifficultLevel?

    override func didMove(to view: SKView) {
        self.easy = self.childNode(withName: "easy") as? SKSpriteNode
        self.middle = self.childNode(withName: "middle") as? SKSpriteNode
        self.hard = self.childNode(withName: "hard") as? SKSpriteNode

    }

    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        for touch in touches {
            let location = touch.location(in: self)
            if (easy?.contains(location))! {
                difficultLevel = .easy
                goToGameScene()
            } else if (middle?.contains(location))! {
                difficultLevel = .middle
                goToGameScene()
            } else if (hard?.contains(location))! {
                difficultLevel = .hard
                goToGameScene()
            }
        }
    }

    func goToGameScene() {
        let gameScene = GameScene(size: self.size)
        let crossFade = SKTransition.crossFade(withDuration: 2)
        self.view?.presentScene(gameScene, transition: crossFade)
    }
}

And I want a different class to access my changed difficultLevel property, but if I create an object in a different class with let getDifficultLevel = Difficulty() and do this:

enum DifficultLevel {
    case easy
    case middle
    case hard
}

class GameScene: SKScene{
    override func didMove(to view: SKView) {
        let getDifficultLevel = Difficulty()
        print(getDifficultLevel.difficultLevel)

        switch getDifficultLevel.difficultLevel {
        case .easy?: spawnTimer = Timer.scheduledTimer(timeInterval: 4, target: self, selector: #selector(self.createEnemy), userInfo: nil, repeats: true)
        case .middle?: spawnTimer = Timer.scheduledTimer(timeInterval: 2, target: self, selector: #selector(self.createEnemy), userInfo: nil, repeats: true)
        case .hard?: spawnTimer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(GameScene.createEnemy), userInfo: nil, repeats: true)
        case .none:
            print("nil!!!!")
        }
    }
}

It always prints nil. I don't understand why although I changed the property in the class Difficulty itself in the function touchesBegan.

Upvotes: 2

Views: 73

Answers (1)

Knight0fDragon
Knight0fDragon

Reputation: 16837

The reason why your .difficultLevel is nil is because you never bother to set it. Learn how to walk through your code.

override func didMove(to view: SKView) {
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
func goToGameScene() {

Are the only functions in your class, and the only one these to set difficulty is touchesBegan.

So let's go to your GameScene function:

 override func didMove(to view: SKView) {

    let getDifficultLevel = Difficulty()
    print(getDifficultLevel.difficultLevel)

    switch getDifficultLevel.difficultLevel {
    case .easy?: spawnTimer = Timer.scheduledTimer(timeInterval: 4, target: self, selector: #selector(self.createEnemy), userInfo: nil, repeats: true)
    case .middle?: spawnTimer = Timer.scheduledTimer(timeInterval: 2, target: self, selector: #selector(self.createEnemy), userInfo: nil, repeats: true)
    case .hard?: spawnTimer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(GameScene.createEnemy), userInfo: nil, repeats: true)
    case .none:
        print("nil!!!!")
    }
}

At what point between:

let getDifficultLevel = Difficulty()
print(getDifficultLevel.difficultLevel)

Does the touchesBegan function get called? (Hint: never)

Now you are most likely going to tell me, "touches begin does get called"

Well where did we go wrong?

let getDifficultLevel = Difficulty() is creating a new scene, not using one already estableshed.

Now I am going to guess that Difficulty is actually your starting scene and you are somehow transitioning to GameScene.

Well you are going to need to pass that data over during transition. I recommend using userData for this.

So when you present your GameScene, you are going to want to do something like this.

//self is the Difficulty scene
let gameScene = GameScene(...)
gameScene.userData = ["difficultLevel":self.difficultLevel]
self.view.presentScene(gameScene)

Then in your GameScene, you want to change your didMove to the following:

override func didMove(to view: SKView) {

    let difficultLevel = userData!["difficultLevel"] as! DifficultLevel //If the code crashed here, this means we have a path that does not set userData, so we need to address that
    print(difficultLevel)

    switch difficultLevel {
    case .easy?: spawnTimer = Timer.scheduledTimer(timeInterval: 4, target: self, selector: #selector(self.createEnemy), userInfo: nil, repeats: true)
    case .middle?: spawnTimer = Timer.scheduledTimer(timeInterval: 2, target: self, selector: #selector(self.createEnemy), userInfo: nil, repeats: true)
    case .hard?: spawnTimer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(GameScene.createEnemy), userInfo: nil, repeats: true)
    case .none:
        print("nil!!!!")
    }
}

Now we have access to the difficult level provided by the previous scene.

Upvotes: 1

Related Questions