Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/445.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/shell/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 使用requestAnimationFrame计算画布中的FPS_Javascript_Html5 Canvas_Requestanimationframe - Fatal编程技术网

Javascript 使用requestAnimationFrame计算画布中的FPS

Javascript 使用requestAnimationFrame计算画布中的FPS,javascript,html5-canvas,requestanimationframe,Javascript,Html5 Canvas,Requestanimationframe,如何计算画布游戏应用程序的FPS?我看过一些例子,但没有一个使用requestAnimationFrame,我不知道如何在那里应用它们的解决方案。这是我的代码: (功能(窗口、文档、未定义){ var canvas=document.getElementById(“mycanvas”), context=canvas.getContext(“2d”), 宽度=画布宽度, 高度=画布高度, fps=0, game_running=正确, show_fps=true; 函数showFPS(){ c

如何计算画布游戏应用程序的FPS?我看过一些例子,但没有一个使用requestAnimationFrame,我不知道如何在那里应用它们的解决方案。这是我的代码:

(功能(窗口、文档、未定义){
var canvas=document.getElementById(“mycanvas”),
context=canvas.getContext(“2d”),
宽度=画布宽度,
高度=画布高度,
fps=0,
game_running=正确,
show_fps=true;
函数showFPS(){
context.fillStyle=“黑色”;
context.font=“正常16pt Arial”;
上下文填充文本(fps+“fps”,10,26);
}
函数gameLoop(){
//清屏
clearRect(0,0,宽度,高度);
如果(show_fps)showFPS();
如果(正在运行游戏)请求动画帧(gameLoop);
}
gameLoop();
}(这个,这个文件)
画布{
边框:3px实心#fd3300;
}

您可以跟踪上一次调用requestAnimFrame的时间

var lastCalledTime;
var fps;

function requestAnimFrame() {

  if(!lastCalledTime) {
     lastCalledTime = Date.now();
     fps = 0;
     return;
  }
  delta = (Date.now() - lastCalledTime)/1000;
  lastCalledTime = Date.now();
  fps = 1/delta;
} 

只需检查AFR回调之间的时间差即可。AFR已经将时间作为参数传递给回调。我更新了你的小提琴来展示它:

只是概念的证明。非常简单的代码。我们所做的就是设置每秒帧数和每帧之间的间隔。在绘图函数中,我们从当前时间中扣除最后一帧的执行时间,以检查从最后一帧开始经过的时间是否超过我们的间隔(基于fps)。如果条件的计算结果为true,我们将为当前帧设置时间,该时间将是下一次图形调用中的“最后一帧执行时间”

var GameLoop = function(fn, fps){
    var now;
    var delta;
    var interval;
    var then = new Date().getTime();

    var frames;
    var oldtime = 0;

    return (function loop(time){
        requestAnimationFrame(loop);

        interval = 1000 / (this.fps || fps || 60);
        now = new Date().getTime();
        delta = now - then;

        if (delta > interval) {
            // update time stuffs
            then = now - (delta % interval);

            // calculate the frames per second
            frames = 1000 / (time - oldtime)
            oldtime = time;

            // call the fn
            // and pass current fps to it
            fn(frames);
        }
    }(0));
};
用法:

var set;
document.onclick = function(){
    set = true;
};

GameLoop(function(fps){
    if(set) this.fps = 30;
    console.log(fps);
}, 5);

我有一种不同的方法,因为如果计算FPS,返回数字时会出现闪烁。我决定数一数每一帧,然后每秒返回一次

window.countFPS = (function () {
  var lastLoop = (new Date()).getMilliseconds();
  var count = 1;
  var fps = 0;

  return function () {
    var currentLoop = (new Date()).getMilliseconds();
    if (lastLoop > currentLoop) {
      fps = count;
      count = 1;
    } else {
      count += 1;
    }
    lastLoop = currentLoop;
    return fps;
  };
}());

requestAnimationFrame(function () {
  console.log(countFPS());
});

Chrome内置fps计数器:

只需打开开发控制台(F12),打开抽屉(Esc),并添加“渲染”选项卡

在这里,您可以激活FPS Meter overlay以查看当前帧速率(包括一个漂亮的图形)以及GPU内存消耗

跨浏览器解决方案: 您可以使用JavaScript库stat.js获得类似的覆盖:

它还为帧率(包括图形)提供了一个很好的覆盖,并且非常易于使用

当比较stats.js和chrome开发工具的结果时,两者显示的测量结果完全相同。因此,您可以信任该库实际执行正确的操作。

不要使用
newdate()
此API有几个缺陷,仅用于获取当前日期+时间。不用于测量时间跨度

Date API使用操作系统的内部时钟,该时钟不断更新并与NTP时间服务器同步。这意味着,该时钟的速度/频率有时比实际时间快,有时慢,因此无法用于测量持续时间和帧率

如果有人更改系统时间(手动或由于DST),如果单个帧突然需要一个小时,您至少可以看到问题。或者是消极的时间。但是,如果系统时钟以20%的速度与世界时间同步,则几乎不可能检测到

此外,DateAPI非常不精确——通常小于1ms。这使得它对于帧率测量尤其无用,因为一个60Hz的帧需要~17ms

相反,使用 Performance API专门针对此类用例开发,可以等效于
new Date()
。只需从其他答案中选择一个,将
新日期()
替换为
性能。现在()
,您就可以开始了

来源:

与Date.now()不同,Performance.now()返回的值 始终以恒定速率增加,与系统时钟无关 (可以手动调整,也可以通过NTP等软件进行调整)。 否则,performance.timing.navigationStart+performance.now()将 大约等于Date.now()

对于windows:

[时间服务]调整本地时钟速率以允许 向正确的时间靠拢。 如果本地时钟和[精确时间采样]之间的时差太大,无法通过调整本地时钟进行校正 时钟频率, 时间服务将本地时钟设置为正确的时间


这里有另一个解决方案:

var times = [];
var fps;

function refreshLoop() {
  window.requestAnimationFrame(function() {
    const now = performance.now();
    while (times.length > 0 && times[0] <= now - 1000) {
      times.shift();
    }
    times.push(now);
    fps = times.length;
    refreshLoop();
  });
}

refreshLoop();
var时间=[];
var-fps;
函数refreshLoop(){
window.requestAnimationFrame(函数(){
const now=performance.now();

虽然(times.length>0&×[0]实际上,没有一个答案对我来说是足够的。下面是一个更好的解决方案:

  • 使用的性能。现在()
  • 计算每秒的实际平均fps
  • 可配置平均每秒数和小数位数
代码:


我缺少一个允许为平均FPS值自定义样本大小的实现。这是我的,它具有以下功能:

  • 准确:基于性能的.now()
  • 稳定:返回的FPS值是平均值(FPS.value | FPS.tick())
  • 可配置:可以自定义FPS样本数组大小(FPS.samplesSize)
  • 高效:用于采集样本的旋转阵列(避免阵列大小调整)
const fps={
样本数量:60,
值:0,
_样本:[],
_索引:0,
_拉斯蒂克:错,
勾选:函数(){
//如果是第一个勾号,只需设置勾号时间戳并返回
如果(!this.\u lastTick\u){
这是。_lastTick_=performance.now();
返回0;
}
//计算ne
// Options
const outputEl         = document.getElementById('fps-output');
const decimalPlaces    = 2;
const updateEachSecond = 1;

// Cache values
const decimalPlacesRatio = Math.pow(10, decimalPlaces);
let timeMeasurements     = [];

// Final output
let fps = 0;

const tick = function() {
  timeMeasurements.push(performance.now());

  const msPassed = timeMeasurements[timeMeasurements.length - 1] - timeMeasurements[0];

  if (msPassed >= updateEachSecond * 1000) {
    fps = Math.round(timeMeasurements.length / msPassed * 1000 * decimalPlacesRatio) / decimalPlacesRatio;
    timeMeasurements = [];
  }

  outputEl.innerText = fps;

  requestAnimationFrame(() => {
    tick();
  });
}

tick();