2
votes

I have created a simple timer in Xcode for a game (SpriteKit):

The variables timer, seconds and score are initialized in the class.

func scoreTimer() {
     timer = Timer.scheduledTimer(timeInterval: 0.05, target: self, selector: #selector(countUp), userInfo: nil, repeats: true)
 }

@objc func countUp() {
     seconds += 0.05
     seconds = (seconds * 100).rounded() / 100
     score = score + 0.015
     updateScore()
 }

 func updateScore() {
     scoreLabel.text = "\(score)"
 }

The timer is started in didMove() when the GameScene has been loaded.

I try to call countUp() every 0.5 seconds. In this function the variable seconds is increased and rounded plus the score variable is increased. From there I would like to call the updateScore function to update the scoreLabel.text - but this doesn't work. The function is called, but the scoreLabel is not updated although when I try to print the score variable, it shows that it is increased constantly.

How can I achieve this and what's is wrong here?

2
Score is getting printed inside updateScore method? - Tushar Sharma
Just noting that 0.05 != 0.5. :) - Phillip Mills

2 Answers

4
votes

I second the statement that Timers should be avoided in Spritekit.

You can also update your label using the update loop.

Controlling the time through your update loop allows you to pause the "timer" if the game is stopped, without having to remove the action from the scene.

You could also have multiple timers running with this method

private var updateTime: Double = 0
private var updateTime2: Double = 0

override func update(_ currentTime: CFTimeInterval) {

   //this will be some sort of variable dictating the state of your game
   guard gameState == .playing else { 
       updateTime = 0
       updateTime2 = 0
       return 
   }

   if updateTime == 0 {
       updateTime = currentTime
   }

   if updateTime2 == 0 {
       updateTime2 = currentTime
   }

   if currentTime - updateTime > 0.5 {
        //do something every half second
        updateTime = currentTime

        score = score + 0.015
        updateScore()
    }

   if currentTime - updateTime2 > 30 {
        //do something every 30 seconds
        updateTime2 = currentTime

        someFunc() 
    }
}
4
votes

Timers should be avoided with SpriteKit unless you are working with technologies outside of SpriteKit. The reason is because SpriteKit has its own time management, and a timer may not coincide with it. Example, in your case, timer updates score. What if you pause the game? Your timer still adds score unless you remember to stop it.

Instead, rely on the actions to do what you need Below is how you do what you are looking for.

let wait = SKAction.wait(forDuration: 0.5)
let update = SKAction.run(
{
        seconds += 0.05
        seconds = (seconds * 100).rounded() / 100
        score = score + 0.015
        updateScore()
}
)
let seq = SKAction.sequence([wait,update])
let repeat = SKAction.repeatForever(seq)
run(repeat)

@RonMyschuk mentioned a thought that I have missed, so I will add it in my answer as well.

If you need to create timers that you can individually pause or pause in a group, then add in extra SKNodes and attach the timer action to the node instead of the scene. Then when you need to pause the timer, you can just pause the node. This will allow your scene update to continue while your timers are paused.