2

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

iCod3r
  • 101
  • 7
  • I would start with the conditions in which the label value would increase. Is it time based (i.e. every 30 seconds the value increases) or progress based? Or based on something else entirely? – Ollie Aug 22 '16 at 12:37
  • @Ollie Sorry for the late answer, the count up timer is progress based i think. Its just a SKLabelNode that goes up and after a certain point it should go up faster as the game scrolls faster to the left (sidescroller) – iCod3r Aug 22 '16 at 18:53

2 Answers2

2

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.

Community
  • 1
  • 1
Whirlwind
  • 14,286
  • 11
  • 68
  • 157
  • That works great! Thank you really much :-) I have a question if you don't mind, i will implement a paused state in my game, how could pause the count up timer and resume it again? And why did you create a player class? Again Thank you really much, i will mark you answer as correct. – iCod3r Aug 22 '16 at 20:11
  • @iCod3r I made an edit to show you how you can grab a specific action and pause it. As far as Player class... Well I made that for me to test it internally and forgot to remove it :) – Whirlwind Aug 22 '16 at 20:21
  • That works too, thank you! Just a simple question left (i know i have many questions, sorry for that) my countUp timer starts with the value "0.15" and then when it reaches 50m it goes "0.14" and by 100m it goes "0.13" and so on. My question is, how can i find out the vaule of the timer during the game? So that if the player pauses the game lets say at 200m and the countUp timer has a value of "0.11" its important that when the player resumes the game that the countUp timer has the same value it had before the paused state, so that the game speed stays the same – iCod3r Aug 22 '16 at 21:12
  • Well you are going a bit into off-topic. Your original question is answered. If you have different questions, feel free to aks a new one, and somebody will hopefully answer it.In short, when player pauses the game, wait action will have the same value for the duration parameter as before. Why do you think that something will change? Anways, you should really ask new question, because we are going into separate topic. Good luck with your game! – Whirlwind Aug 22 '16 at 21:45
  • Ooh yeah sorry, you're right! I mistook the speed value with the wait action/duration value. Regardless, i don't have questions about this topic anymore. You're awesome dude, i wish i could upvote you answer more than one time :-) Thank you! – iCod3r Aug 22 '16 at 22:57
0

You can use NSTimer and update the value every x seconds. Create your NSTimer when the game starts

var timer = NSTimer.scheduledTimerWithTimeInterval(0.4, target: self, selector: #selector(MyGame.countUp), userInfo: nil, repeats: true)

and then create a function in the same class that counts the value up by e.g. 1

func countUp() {
    self.myCountLabel.text == "\(1 + self.myCountLabel.text ?? 0)"
}
Yannick
  • 3,210
  • 1
  • 21
  • 30
  • 2
    In SpriteKit more appropriate way is to use SKAction or update: method. NSTimer is not affected by view's or scene's paused state so automatic pausing/unpausing wont work when user receive a phone call or some other interrupt occur. – Whirlwind Aug 22 '16 at 12:59
  • You could, however, invalidate the timer when something interrupts. Even though I agree – Yannick Aug 22 '16 at 13:04
  • Thank you for you answer Yannick, but like @Whirlwind said NSTimer is not affected by view's state so its not suitable for me. – iCod3r Aug 22 '16 at 13:09
  • @Yannick, it becomes more involved than that, you need to retain the time that has already passed, then fire a timer on return for the difference, followed by restarting the normal timer, major pain to do correctly. – Knight0fDragon Aug 22 '16 at 13:50
  • @Whirlwind I took a look at your post and tried to implement it, i had to modify a few things to get it worked correctly so that it fits to my game. Im gonna report it to you in a few hours if you don't mind, unfortunately i have to go now. – iCod3r Aug 22 '16 at 15:07