Javascript 使用requestAnimationFrame计算画布中的FPS
如何计算画布游戏应用程序的FPS?我看过一些例子,但没有一个使用requestAnimationFrame,我不知道如何在那里应用它们的解决方案。这是我的代码: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
(功能(窗口、文档、未定义){
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();