在 Canvas 中使用带有 requestAnimationFrame 的 JS 倒数计时器
Use JS countdown timer in Canvas with requestAnimationFrame
我正在制作一个简单的 canvas- 游戏,我正在为游戏循环使用 requestAnimationFrame(Paul Irish 的版本)。我在游戏中使用 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/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
忘记补充了。
您永远无法通过该方法获得百分之一秒的精度。您将平均延迟 7-8 毫秒。但是除非你让它变得更复杂,否则这是你能做的最好的。 7-8ms 的平均值是恒定的,并且在 2 小时 1 秒内是相同的,并且仅由大约 16 ms 的动画刷新时间决定。
我正在制作一个简单的 canvas- 游戏,我正在为游戏循环使用 requestAnimationFrame(Paul Irish 的版本)。我在游戏中使用 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/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
忘记补充了。
您永远无法通过该方法获得百分之一秒的精度。您将平均延迟 7-8 毫秒。但是除非你让它变得更复杂,否则这是你能做的最好的。 7-8ms 的平均值是恒定的,并且在 2 小时 1 秒内是相同的,并且仅由大约 16 ms 的动画刷新时间决定。