iCod3r iCod3r - 3 months ago 16
iOS Question

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

Answer

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 to 1.0

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

let countUpActionKey = "countUp"

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

Comments