0

我正在製作一個簡單的畫布遊戲,並且我正在使用requestAnimationFrame(Paul Irish的版本)作爲gameloop。我在遊戲中使用了javascript倒計時(顯示秒和100秒),但它不以正確的速度倒計時。我知道這與遊戲的刷新率有關,因此計數器會更新每一幀,而不是每隔100秒。我該如何解決?使用requestAnimationFrame在畫布中使用JS倒數計時器

這裏的計時器對象:

/** 
* 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(); 
    }, 
} 

而且gameloop和部分調用定時器:

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(); 
    }; 

我也嘗試以此爲timer-對象,但是在調試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

requestAnimationFrame將時間以毫秒爲單位傳遞給它作爲第一個參數調用的函數。 '函數myLoop(time){requestAnimationFrame(myLoop)}'使用'setInterval'特別是在這麼短的時間間隔內會要求麻煩,因爲任何延遲瀏覽器1/100秒的事情最終都會試圖追趕和如果您有一段時間需要渲染的動畫會導致瀏覽器崩潰。避免使用'setInterval'來比任何短於瀏覽器的東西。 – Blindman67

+0

@ Blindman67任何建議如何以另一種方式解決這個問題? – Sluggo

回答

3

不確定您是要求以1/100間隔顯示時間,還是使用setInterval時間不準確。

答: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 

忘了補充

最好的方式得到一個倒計時。

你永遠不會通過該方法獲得100秒的精度。你將平均7-8毫秒。但除非你讓它變得複雜得多,這是你能做的最好的。 7-8ms的平均值是恆定的,2小時和1秒相同,並且僅由大約16ms的動畫刷新時間確定。

+0

謝謝,看起來不錯!但有一個問題:參數計時器有什麼作用? - 沒有參數被髮送到函數,但它需要這個參數。它從哪裏獲得它的價值? – Sluggo

+1

@Sluggo時間在瀏覽器調用通過'requestAnimationFrame'設置的回調函數時作爲參數傳遞。現在是1/1000秒的時間,大多數瀏覽器現在可以精確到1,000,000秒,通過額外的精度表示爲小數分量,因此100.055的值爲100,055/1,000,000。時間是頁面啓動以來的時間,雖然頁面啓動時我不知道。您可以通過將其與Date.now()進行比較並將該偏移量用於頁面的生命週期來實時同步它。 – Blindman67