00Gheist00
00Gheist00

Reputation: 145

Stopping timer not working:

I have THIS timer in my project. When it runs out, it shows a Time Up screen, which works fine. But when the player is Game Over, i show the Game Over screen, but the timer keeps running and when it hits 00:00 then it switches to the Time Up screen.

How can i make this timer stop counting down and set to 00:00 again?

I tried adding a function like this:

CountDownTimer.prototype.stop = function() {
  diff = 0;
  this.running = false;    
};

I also tried to change the innerHTML but its obvious that its just changing the numbers without stopping the timer and after a second it will show the count down again... I don't know what to call.

//Crazy Timer function start
function CountDownTimer(duration, granularity) {
  this.duration = duration;
  this.granularity = granularity || 1000;
  this.tickFtns = [];
  this.running = false;
}

CountDownTimer.prototype.start = function() {
  if (this.running) {
    return;
  }
  this.running = true;
  var start = Date.now(),
      that = this,
      diff, obj;

  (function timer() {
    diff = that.duration - (((Date.now() - start) / 1000) | 0);

    if (diff > 0) {
      setTimeout(timer, that.granularity);
    } else {
      diff = 0;
      that.running = false;
    }

    obj = CountDownTimer.parse(diff);
    that.tickFtns.forEach(function(ftn) {
      ftn.call(this, obj.minutes, obj.seconds);
    }, that);
  }());
};

CountDownTimer.prototype.onTick = function(ftn) {
  if (typeof ftn === 'function') {
    this.tickFtns.push(ftn);
  }
  return this;
};

CountDownTimer.prototype.expired = function() {
  return !this.running;
};

CountDownTimer.parse = function(seconds) {
  return {
    'minutes': (seconds / 60) | 0,
    'seconds': (seconds % 60) | 0
  };
};

window.onload = function () {
    var display = document.querySelector('#countDown'),
        timer = new CountDownTimer(timerValue),
        timeObj = CountDownTimer.parse(timerValue);

    format(timeObj.minutes, timeObj.seconds);

    timer.onTick(format).onTick(checkTime);

    document.querySelector('#startBtn').addEventListener('click', function () {
        timer.start();
    });

    function format(minutes, seconds) {
        minutes = minutes < 10 ? "0" + minutes : minutes;
        seconds = seconds < 10 ? "0" + seconds : seconds;
        display.textContent = minutes + ':' + seconds;
    }

    function checkTime(){
    if(this.expired()) {
        timeUp();
        document.querySelector('#startBtn').addEventListener('click', function () {
        timer.start();
    });
    }
    }
};

Upvotes: 0

Views: 174

Answers (3)

tozer83
tozer83

Reputation: 24

It's been a while and I'm not sure if you've figured it out but check out the fiddle below: https://jsfiddle.net/f8rh3u85/1/

// until running is set to false the timer will keep running
if (that.running) {
    if (diff > 0) {
      setTimeout(timer, that.granularity);
    } else {
      diff = 0;
      that.running = false;
    }

    obj = CountDownTimer.parse(diff);
    that.tickFtns.forEach(function(ftn) {
      ftn.call(this, obj.minutes, obj.seconds);
    }, that);
}

I've added a button that causes running to be set to false which stops the timer.

Button:

<button id="stop">Game Over</button>

Code:

$( "#stop" ).click(function() {
    timer.running = false;
});

So that should hopefully get you to where you need to be.

Upvotes: 1

Ian Thomas
Ian Thomas

Reputation: 656

Similar to Tom Jenkins' answer, you need to cancel the next tick by avoiding the diff > 0 branch of your if statement. You could keep your code as it stands and use your suggested stop method, however, you'd need to change your logic around handling ticks to check that both running === true and a new param gameOver === false.

Ultimately, I think your problem is that no matter whether the timer is running or not, you'll always execute this code on a tick:

obj = CountDownTimer.parse(diff);
that.tickFtns.forEach(function(ftn) {
  ftn.call(this, obj.minutes, obj.seconds);
}, that);

If you have a game over state, you probably don't want to call the provided callbacks, so add some conditional check in there.

Upvotes: 0

Tom Jardine-McNamara
Tom Jardine-McNamara

Reputation: 2608

Instead of recursively calling setTimeout, try setInterval instead. You could then store a reference to the timer:

this.timer = setInterval(functionToRunAtInterval, this.granularity);

and kill it when the game finishes::

clearInterval(this.timer)

(see MDN's docs for more info on setInterval)

Upvotes: 2

Related Questions