检查JS中的FPS?

时间:2011-01-24 21:35:37

标签: javascript html html5 canvas

我如何查看我的javascript的fps?我正在使用它循环:

gameloopId = setInterval(gameLoop, 10);

5 个答案:

答案 0 :(得分:92)

@Slaks的代码只给出了最后一帧的瞬时FPS,这可能会因打嗝而变化或误导。我更喜欢使用易于编写和计算的低通滤波器来消除快速瞬变并显示最近结果的合理伪平均值:

// The higher this value, the less the fps will reflect temporary variations
// A value of 1 will only keep the last value
var filterStrength = 20;
var frameTime = 0, lastLoop = new Date, thisLoop;

function gameLoop(){
  // ...
  var thisFrameTime = (thisLoop=new Date) - lastLoop;
  frameTime+= (thisFrameTime - frameTime) / filterStrength;
  lastLoop = thisLoop;
}

// Report the fps only every second, to only lightly affect measurements
var fpsOut = document.getElementById('fps');
setInterval(function(){
  fpsOut.innerHTML = (1000/frameTime).toFixed(1) + " fps";
},1000);

此过滤器的“半衰期” - 从旧值中间移动到新的稳定值所需的帧数是filterStrength*Math.log(2)(约为强度的70%)。

例如,20的强度将在中途移动到14帧的瞬时变化,在28帧中的3/4,在46帧中的90%,以及99%的在92帧的方式。对于一个运行速度大约为30fps的系统,性能的突然剧烈变化将在半秒内显现出来,但仍然会“抛弃”单帧异常,因为它们只会将值偏移5%。

这是一个~30fps游戏的不同过滤器强度的视觉比较,其瞬间下降到10fps,然后速度高达50fps。正如您所看到的,较低的滤波器值更快地反映了“良好”的变化,但也更容易受到临时打嗝的影响:
enter image description here

最后,an example使用上面的代码来实际对“游戏”循环进行基准测试。

答案 1 :(得分:25)

gameLoop中,查看最后一个循环中new Datenew Date之间的差异(将其存储在变量中)。
换句话说:

var lastLoop = new Date();
function gameLoop() { 
    var thisLoop = new Date();
    var fps = 1000 / (thisLoop - lastLoop);
    lastLoop = thisLoop;
    ...
}

thisLoop - lastLoop是两个循环之间传递的毫秒数。

答案 2 :(得分:2)

我用它来计算fps

  var GameCanvas = document.getElementById("gameCanvas");
  var GameContext = doContext(GameCanvas,"GameCanvas");
  var FPS = 0;
  var TimeNow;
  var TimeTaken;
  var ASecond = 1000;
  var FPSLimit = 25;
  var StartTime = Date.now();
  var TimeBefore = StartTime;
  var FrameTime = ASecond/FPSLimit;
  var State = { Title:0, Started:1, Paused:2, Over:3 };
  var GameState = State.Title;

  function gameLoop() {
    requestAnimationFrame(gameLoop);
    TimeNow = Date.now();
    TimeTaken = TimeNow - TimeBefore;

    if (TimeTaken >= FrameTime) {
      FPS++
      if((TimeNow - StartTime) >= ASecond){
        StartTime += ASecond;
        doFPS();
        FPS = 0;
      }

      switch(GameState){
        case State.Title :
          break;
        case State.Started :
          break;
        case State.Paused :
          break;
        case State.Over :
          break;
      }
      TimeBefore = TimeNow - (TimeTaken % FrameTime);
    }
  }

  Sprites.onload = function(){
    requestAnimationFrame(gameLoop);
  }

  function drawText(Context,_Color, _X, _Y, _Text, _Size){
    Context.font =  "italic "+ _Size +" bold";
    Context.fillStyle = _Color;
    Context.fillText(_Text, _X, _Y);
  }

  function doFPS()(
    drawText(GameContext,"black",10,24,"FPS : " + FPS,"24px");
  }

  function doContext(Canvas,Name){
    if (Canvas.getContext) {
      var Context = Canvas.getContext('2d');
      return Context;
    }else{
      alert( Name + ' not supported your Browser needs updating');
    }
  }

答案 3 :(得分:2)

requestAnimationFrame怎么办?

var before,now,fps;
before=Date.now();
fps=0;
requestAnimationFrame(
    function loop(){
        now=Date.now();
        fps=Math.round(1000/(now-before));
        before=now;
        requestAnimationFrame(loop);
        console.log("fps",fps)
    }
 );

答案 4 :(得分:0)

我的2美分:

对我来说比较优化很有用。 当然,仅消耗一些资源即可进行测试。

理想情况下,当使用事件,循环等时,在充分使用的情况下,您的应用帧速率应保持每秒50帧以上。

无论如何,至少在现在,屏幕刷新不会超过60hz。

人类感觉落后于24 FPS,这是 1000/24 = 41ms

因此,在静止感之前,帧的最后一个最低点是41ms。

let be = Date.now(),fps=0;
requestAnimationFrame(
    function loop(){
        let now = Date.now()
        fps = Math.round(1000 / (now - be))
        be = now
        requestAnimationFrame(loop)
        if (fps < 35){
          kFps.style.color = "red"
          kFps.textContent = fps 
        } if (fps >= 35 && fps <= 41) {
            kFps.style.color = "deepskyblue"
            kFps.textContent = fps + " FPS"
          } else {
            kFps.style.color = "black"
            kFps.textContent = fps + " FPS"
        }
        kpFps.value = fps
    }
 )
<span id="kFps"></span>
<progress id="kpFps" value="0" min="0" max="100" style="vertical-align:middle"></progress>

只是一个循环就可以了,间隔为50ms,应该保持平稳! 看到进度条跳了吗? 这是丢帧,浏览器试图通过牺牲来跟上,跳到下一帧,我们必须避免这种情况!

let t
for (let i=0;i<99999;i++){
  t = setTimeout(function(){
   console.log("I am burning your CPU! " + i)
   clearTimeout(t)
  },50)
  
}