【问题标题】:Creating a stopwatch/timer along with canvas animation at 60fps创建秒表/计时器以及 60fps 的画布动画
【发布时间】:2015-01-23 22:31:31
【问题描述】:

我正在尝试在一些画布动画旁边创建一个计时器。动画使用设置为 60 fps 的函数循环来刷新画布并重绘对象。我能想到制作秒表的唯一方法是使用相同的循环来获取每帧的毫秒数并将其添加到文本对象中。我只是想知道是否有更有效的方法来做到这一点?

var frame = 0;
canvas.setLoop(function() {
    if(particle.x < 1080 && particle.x > 0){
        frame++;
        particle.x = 540 + (acc*frame*frame)/120;
        gField.t.text = "g = 9.81ms⁻²\nMass = "+particle.mass+"kg\nF = ma\nFrame: " + frame + "\nDistance: " + (particle.x - 540).toFixed(1);
        stopwatch();
    }else{
        canvas.timeline.stop();
    }
})
var sec = 0;
var tsec = 0;
var hsec = 0;
function stopwatch(){
    hsec+= (5/3);
    if(hsec >= 10){
        tsec++;
        hsec = hsec -10;
    }
    if(tsec >= 10){
        sec++;
        tsec = tsec-10;
    }
    time.text = (sec)+":"+(tsec)+(hsec).toFixed(0);
}
var clicks = 0
control.button.bind("click tap", function() {
    clicks++;
    if(clicks == 1){
        canvas.timeline.start();
    }else{
        clicks = 0;
        canvas.timeline.stop();
    }
})

附:这是一个动力学模拟程序。我正在为画布动画使用 oCanvas 库。

【问题讨论】:

  • 请记住,您没有 60fps 的保证。如果 f.e. 它可以下降。你的客户端电脑很慢。你必须用 Date() 检查时间以获得正确的时间。
  • 也许这可能有助于获取客户端的 FPS:stackoverflow.com/a/4787460/648350

标签: javascript jquery html animation canvas


【解决方案1】:

使用 requestAnimationFrame,因为这是您使用 JavaScript 可以获得的最准确的计时器,而且它会为您提供高分辨率的时间戳:

var ctx = canvas.getContext('2d'),
  startTime = null,
  lastTime = null,  // for scale
  isRunning = false,
  FPS = 1000/60,
  x = 0,
  dx = 4; // ideal frame rate

function loop(timeStamp) {

  if (!startTime) startTime = timeStamp;
    

  var timeDiff = lastTime ? timeStamp - lastTime : FPS,
      timeElapsed = timeStamp - startTime,
      timeScale = timeDiff / FPS; // adjust variations in frame rates

  lastTime = timeStamp;
  
  ctx.clearRect(0,0,canvas.width, canvas.height);

  // do your stuff using timeScale, ie:
  // pos.x += velocity.x * timeScale
  x += dx * timeScale;
  if (x < 0 || x > canvas.width-1) dx = -dx;
  
  ctx.fillRect(x,0,8,8);
  ctx.fillText((timeElapsed*0.001).toFixed(4), 10, 50);
  ctx.fillText(timeScale.toFixed(1), 10, 90);

  if (isRunning) requestAnimationFrame(loop);
}

ctx.font = "40px sans-serif";

btnToggle.addEventListener("click", function() {
  if (isRunning) {
    isRunning = false;
    this.innerHTML = "Start";
  } else {
    startTime = lastTime = null;
    isRunning = true;
    requestAnimationFrame(loop)
    this.innerHTML = "Stop";
  }
}, false);
<canvas id=canvas width=360 height=100></canvas>
<br><button id="btnToggle">Start</button>

要重置开始时间,请将其初始化为 null(或 0)。 isRunning 在这里用作一个示例,说明如何停止循环(通过将其设置为 false)。

请注意,timeScale 用于补偿帧速率变化。如果循环没有以 60 FPS 运行,那么timeScale 将对此进行补偿,即。如果 FPS 为 30 timeScale 将是 2 等等,这样您就可以根据时间正确更新参数。

【讨论】:

  • 是的!这看起来非常适合我想做的事情。谢谢
  • 调用循环函数时看不到timeStamp是如何初始化的
  • requestAnimationFrame(loop) 开始循环。 rAF 将对其进行初始化。希望这会有所帮助!
  • 谢谢。所以我猜测时间戳是每次调用 raf 之间的时间?
  • @JimiiBee 这是从循环开始经过的时间。只需减去循环停止时的开始时间即可获得差异。您也可以改用performance.now()(rAF 在内部使用它)。不过,较旧的浏览器可能不支持此功能。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-07-23
  • 2018-12-14
  • 1970-01-01
  • 2019-04-03
  • 1970-01-01
相关资源
最近更新 更多