Search code examples
iosswiftsprite-kitprogress-barcountdown

How to make a reversed countdown or a count up timer in swift?


Im working on a 2d platformer game and what i need is a count up timer aka a progress bar or a progress count node. It should should work exactly like a countdown except it should start at 0 and go endlessly up. I will base the game speed/difficulty depending on how high that number is. I know to ask questions in SO you should always provide some code, but i have know clue how to make a reversed countdown. Does someone now how to create something like this shown in the screenshots below?

EDIT

I've managed to kinda achieve what i wanted. I just created a SKLabelNode that has a int variable as a text and in the update method increased the int variable like that --score++--. But the value of the score label increases really fast, does someone know how slow it down a little bit and then after a time make it slowly faster as the game goes further?

Thank you in advance.

enter image description here enter image description here

enter image description here enter image description here

enter image description here


Solution

  • Maybe something like this :

    import SpriteKit
    
    class Player:SKSpriteNode {
    
        override init(texture: SKTexture?, color: UIColor, size: CGSize) {
            super.init(texture: texture, color: color, size: size)
        }
    
        required init?(coder aDecoder: NSCoder) {
            fatalError("init(coder:) has not been implemented")
        }
    }
    
    class GameScene: SKScene, SKPhysicsContactDelegate {
    
        var gameStarted = false
        var player = Player(texture: nil, color: UIColor.brownColor(), size: CGSize(width: 50, height: 100))
    
        var levelTimerLabel = SKLabelNode()
        var levelTimerValue: Int = 0 {
            didSet {
    
                if levelTimerValue == 10 { self.increaseScore(withDelay: 0.1)}
                levelTimerLabel.text = "\(levelTimerValue)m"
            }
        }
    
        override func didMoveToView(view: SKView) {
    
            self.player.position = CGPoint(x: CGRectGetMidX(frame), y: CGRectGetMidY(frame))
            addChild(self.player)
    
            levelTimerLabel.zPosition = 200
            levelTimerLabel.position = CGPoint(x: CGRectGetMidX(frame), y: CGRectGetMidY(frame))
            levelTimerLabel.text = "\(levelTimerValue)m"
            addChild(levelTimerLabel)
        }
    
        //MARK: SCORELABEL METHOD
        func increaseScore(withDelay delay:NSTimeInterval = 0.5) {
    
            let block = SKAction.runBlock({[unowned self] in
                self.levelTimerValue += 1 // Swift 3 yo
            })
    
            let wait = SKAction.waitForDuration(delay)
    
            let sequence = SKAction.sequence([wait,block])
    
            self.runAction(SKAction.repeatActionForever(sequence), withKey: "countUp")
    
        }
        override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
            if gameStarted == false {
    
                gameStarted = true
                startWorld()
                increaseScore()
            }
           player.physicsBody?.velocity = CGVectorMake(0, 0)
           player.physicsBody?.applyImpulse(CGVectorMake(0, 150))  // Jump Impulse
        }
    
        func startWorld(){
    
            print("startWold method invoked")
        }
    }
    

    When the levelTimerValue reaches 10, the countUp action will be replaced with a new one, which is going to be 5 times faster. I guess that is what you were trying to achieve. I modified your code a bit to avoid strong reference cycles, removed unneeded update: method calls and few minor things as well. Also note that now you don't have a SKAction property called "wait". That action is created locally now.

    EDIT:

    Based on your comments, you can pause the timer like this :

     func pauseTimer(){
    
            if let countUpAction = self.actionForKey("countUp") {
    
                countUpAction.speed = 0.0
            }
    
        }
    

    Unpausing would be the same...Just set countUpAction.speed to 1.0 If you want to pause the whole game take a look at this SO question. Take a look at @Knight0fDragon's answer. That is a nice way to go, and IMO, it is more flexible than pausing a scene or a view completely.

    Also instead of using string "countUp" I suggest you to make a constant like this:

    let kCountUpActionKey = "countUp"
    

    so you will be safe from typos when reusing this action key.