Search code examples
swiftsprite-kitsknodesklabelnode

Updating SKLabel text through an SKNode subclass


My Goal: add one to the amount variable of the Achievements Class and then update the text so it shows on the SKLabelNode called "AmountLabel"

So I have a subclass of SKNode that shelters my SKSpriteNode that shows the emblem of the achievement and the SKLabelNodes of the title of the achievement and the amount needed to unlock the achievement As seen below:

class Achievements: SKNode {

var achievementLabel = SKLabelNode()
var achievementTitleLabel = SKLabelNode()
var achievementNode = SKSpriteNode()

var amount = 0
var neededAmount = 0

var Image: String = "locked" {
    didSet {
       var texture = SKTexture(imageNamed: Image)
    }
}

func createAchievement() {

    let tex:SKTexture = SKTexture(imageNamed: Image)

    achievementNode = SKSpriteNode(texture: tex, color: SKColor.black, size: CGSize(width: 75, height: 75))  //frame.maxX / 20, height: frame.maxY / 20))
    achievementNode.zPosition = -10
    achievementNode.name = "AchievementNode"

    amount = 0
    neededAmount = 10

    self.addChild(achievementNode)
    self.zPosition = -11
    Achievements3.append(achievementNode)

    createAchievementLabels()
}

func createAchievementLabels() {

    achievementTitleLabel = SKLabelNode(fontNamed: "Avenir-Black")
    achievementTitleLabel.fontColor = UIColor.black;
    achievementTitleLabel.fontSize = 13 //self.frame.maxY/30
    achievementTitleLabel.position = CGPoint (x: 0, y: 45)
    achievementTitleLabel.text = "COLLECTOR"
    achievementTitleLabel.zPosition = -9
    addChild(achievementTitleLabel)

    achievementTitleLabel.name = "AchievementTitleLabel"

    achievementLabel = SKLabelNode(fontNamed: "Avenir-Black")
    achievementLabel.fontColor = UIColor.black;
    achievementLabel.fontSize = 13 //self.frame.maxY/30
    achievementLabel.position = CGPoint (x: 0, y: -50)
    achievementLabel.text = ("\(amount) / \(neededAmount)")
    achievementLabel.zPosition = -9
    addChild(achievementLabel)

    achievementLabel.name = "AmountLabel"
    AchievementLabels.append(achievementLabel)

}

func UpdateText() {

    achievementLabel.text = ("\(amount) / \(neededAmount)")

   }

}

they're are then added in another class called AchievementMenu like so:

for 0...12 {

     let Achievement = Achievements()
     Achievement.createAchievement()
     Achievement.position = CGPoint(x: self.frame.midX, y: self.frame.midY)
     Achievement.zPosition = 100
     moveableArea.addChild(Achievement)
}

Then in another function in the AchievementMenu class I'm trying to enumerate through the the node tree to be able to update the label to add one to its amount variable and then updates its text like so:

 func addOneToAchievementAndUpdateText() {

    moveableArea.enumerateChildNodes(withName: "SKNode") {
        node, stop in

        let LabelAmount:Achievements = node as! Achievements

        node.enumerateChildNodes(withName: "AmountLabel") {
            node, stop in

            LabelAmount.amount += 1
            LabelAmount.UpdateText()

        }
    }
}

but every time i try and cast a variable as an actual class it gives me an error:

Could not cast value of type 'SKLabelNode' (0x10e5edb08) to 'Astrum.Achievements' (0x10c899438).

How do I add one to the amount variable and then update the text so it shows the new amount on the screen?


Solution

  • To avoid the casting error you can check the node type as:

    func addOneToAchievementAndUpdateText() {
    
        moveableArea.enumerateChildNodes(withName: "SKNode") {
            node, stop in
            print("- node type is: \(type(of: node))")
            if node is Achievements {
                let achievements = node as! Achievements
                achievements.amount += 1
                achievements.UpdateText()
            }
        }
    }
    

    Your mistake would not have appeared if you put after the line:

    Achievement.zPosition = 100
    

    this line:

    Achievement.name = "SKNode"
    

    P.S. Don't forget to use lowercase for variables to don't confused these one with class types: generally it's considered as a bad attitude..