37

キャンバス ゲーム アプリケーションの FPS を計算するにはどうすればよいですか? いくつかの例を見てきましたが、それらのどれも requestAnimationFrame を使用しておらず、そこにソリューションを適用する方法がわかりません。これは私のコードです:

(function(window, document, undefined){

    var canvas       = document.getElementById("mycanvas"),
        context      = canvas.getContext("2d"),
        width        = canvas.width,
        height       = canvas.height,
        fps          = 0,
        game_running = true,
        show_fps     = true;

    function showFPS(){
        context.fillStyle = "Black";
        context.font      = "normal 16pt Arial";

        context.fillText(fps + " fps", 10, 26);
    }
    function gameLoop(){

        //Clear screen
        context.clearRect(0, 0, width, height);

        if (show_fps) showFPS();

        if (game_running) requestAnimationFrame(gameLoop);

    }
    
    gameLoop();

}(this, this.document))
canvas{
    border: 3px solid #fd3300;
}
<canvas id="mycanvas" width="300" height="150"></canvas>

ところで、パフォーマンスを監視するために追加できるライブラリはありますか?

4

11 に答える 11

25

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

http://jsfiddle.net/vZP3u/

于 2011-11-26T17:20:05.843 に答える
8

FPSを計算すると、数値を返すときにこのちらつきが発生するため、別のアプローチがあります。すべてのフレームをカウントし、1 秒に 1 回返すことにしました

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

jsfiddle

于 2013-11-04T19:28:41.460 に答える
4

実際、私にとって十分な答えはありませんでした。これはより良い解決策です:

  • 使用の performance.now()
  • 1 秒あたりの実際の平均fps を計算します
  • 1 秒あたりの平均と小数点以下の桁数を設定可能

コード:

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

JSFiddle

于 2018-10-09T18:27:36.683 に答える
3

単なる概念実証。非常に単純なコード。1 秒あたりのフレーム数と各フレーム間の間隔を設定するだけです。描画関数では、現在の時間から最後のフレームの実行時間を差し引いて、最後のフレームからの経過時間が間隔 (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);

http://jsfiddle.net/ARTsinn/rPAeN/

于 2013-04-06T13:32:33.127 に答える
3

AFR コールバック間の時間差を確認するだけです。AFR はすでに時間を引数としてコールバックに渡しています。それを表示するためにフィドルを更新しました:http://jsfiddle.net/WCKhH/1/

于 2011-11-26T17:24:53.030 に答える