代码之家  ›  专栏  ›  技术社区  ›  Sluggo

在带有requestAnimationFrame的Canvas中使用JS倒计时计时器

  •  0
  • Sluggo  · 技术社区  · 9 年前

    我正在制作一个简单的画布游戏,我正在使用requestAnimationFrame(PaulIrish的版本)进行游戏循环。我在游戏中使用了javascript倒计时(显示秒和100秒),但它没有以正确的速度倒计时。我知道这与游戏的刷新率有关,所以计数器每帧更新一次,而不是每100秒更新一次。我该如何解决这个问题?

    下面是计时器对象:

    /**
     * The timer as an object
    */
    function Timer(position, time) {
      this.position = position || new Vector(150,210);
      this.time = time || 6000;
    }
    
    Timer.prototype = {
      start: function() {
        console.log('start running');
        this.initial = this.time; //time in 100'ths of seconds
        this.count = this.initial;
        this.counter; //10 will  run it every 100th of a second
        clearInterval(this.counter);
        //this.counter = setInterval(this.timer, 10);
        this.timer();
      },
    
      timer: function() {
        //console.log(this.count);
        this.count--;
          var res = this.count / 100;
        //Show counter in canvas
        return 'Tid kvar: ' + res.toPrecision(this.count.toString().length) + ' sekunder';
      },
    
      draw: function(ct) {
        if(this.initial === undefined){this.start();} //Start the timer
        ct.save();
        if(this.count <=0){ //Remove timer if timer has reached 0
          ct.clearRect(this.position.x, this.position.y, Racetrack.innerTrackWidth, Racetrack.innerTrackHeight);
          return false;
        } else { //draw timer
          ct.save();
          ct.font = 'bold 3em arial';
          ct.fillStyle = 'orange';
          ct.fillText(this.timer(), this.position.x, this.position.y);
        }
        ct.restore();
      }, 
    }
    

    游戏循环和调用计时器的部分:

      var init = function(canvas) {
        timer = new Timer(new Vector(160,210), 3000);
      }
    
      var render = function() {
        ct.clearRect(0,0,width,height);
        ship.draw(ct);
        racetrack.draw(ct);
        //draw timer or results if timer reached 0
        timer.draw(ct) !=false ? timer.draw(ct) : endFrame.draw(ct);
      };
    
      var gameLoop = function() {
        var now = Date.now();
        td = (now - (lastGameTick || now)) / 1000; // Timediff since last frame / gametick
        lastGameTick = now;
        if(timer.draw(ct) == false) { //stop the game if timer has reached 0.
          cancelRequestAnimFrame(gameLoop);
          console.log('Time\'s up!');
        } else { //Otherwise, keep the game going.
          requestAnimFrame(gameLoop);
        }
        update(td);
        render();
      };
    

    我也尝试过将其作为计时器对象,但是调试 this.count 显示了第一个循环的编号,未定义第二个循环,之后的每个循环都是NaN(我不确定这会不会解决计时问题?):

    function Timer(position, time) {
      this.position = position || new Vector(150,210);
      this.time = time || 6000;
    }
    
    Timer.prototype = {
      start: function() {
        console.log('start running');
        this.initial = this.time; //time in 100'ths of seconds
        this.count = this.initial;
        this.counter; //10 will  run it every 100th of a second
        clearInterval(this.counter);
        this.counter = setInterval(this.timer, 10);
        this.timer();
      },
    
    
      timer: function() {
        console.log(this.count);
        this.count--;
      },
    
      getTime: function() {
        var res = this.count / 100;
        return 'Tid kvar: ' + res.toPrecision(this.count.toString().length) + ' sekunder';
      },
    
      draw: function(ct) {
        if(this.initial === undefined){this.start();} //Start the timer
        ct.save();
        if(this.count <=0){ //Remove timer if timer has reached 0
          ct.clearRect(this.position.x, this.position.y, Racetrack.innerTrackWidth, Racetrack.innerTrackHeight);
          return false;
        } else { //draw timer
          ct.save();
          ct.font = 'bold 3em arial';
          ct.fillStyle = 'orange';
          ct.fillText(this.getTime(), this.position.x, this.position.y);
        }
        ct.restore();
      },
    }
    
    1 回复  |  直到 9 年前
        1
  •  3
  •   Blindman67    9 年前

    不确定您是要求以1/100间隔显示时间,还是使用setInterval时时间不准确。

    A: setInterval不应该用于计时,因为它远不准确,而且间隔越小越差,如果动画正在运行,情况就更糟。

    B: 浏览器在1/60秒刷新。您可以强制显示器以1/100秒的速度渲染和显示,但根据图形硬件的不同,它可能永远不会显示,因为此时显示器正在扫描屏幕上其他位置的像素。或者,当您在图形写入显示器时覆盖显示器时,会出现剪切。

    使用requestAnimationFrame获取倒计时的最佳方式

    var start = true;     // flags that you want the countdown to start
    var stopIn = 3000;    // how long the timer should run
    var stopTime = 0;     // used to hold the stop time
    var stop = false;     // flag to indicate that stop time has been reached
    var timeTillStop = 0; // holds the display time
    
    // main update function
    function update(timer){
    
        if(start){  // do we need to start the timer
            stopTime = timer + stopIn; // yes the set the stoptime
            start = false;             // clear the start flag
        }else{                         // waiting for stop
            if(timer >= stopTime){     // has stop time been reached?
                stop = true;           // yes the flag to stop
            }
        }
    
        timeTillStop = stopTime - timer;      // for display of time till stop
        // log() should be whatever you use to display the time.
        log(Math.floor(timeTillStop / 10) );  // to display in 1/100th seconds
    
        if(!stop){
            requestAnimationFrame(update); // continue animation until stop 
        }
    }
    requestAnimationFrame(update);  // start the animation
    

    忘记添加。

    通过这种方法,你永远不会获得百分之一百秒的准确度。你的平均时间为7-8毫秒。但除非你把它做得更复杂,否则这是你能做的最好的。7-8ms的平均值是恒定的,并且在2小时1秒内是相同的。