Wie würde ich die Framerate in meinem Javascript-Code überprüfen? Ich verwende dies zum Schleifen:
gameloopId = setInterval(gameLoop, 10);
CyanPrime
Wie würde ich die Framerate in meinem Javascript-Code überprüfen? Ich verwende dies zum Schleifen:
gameloopId = setInterval(gameLoop, 10);
Phrogz
Der Code von @Slaks gibt Ihnen nur die momentanen FPS des letzten Frames, die variieren oder mit Schluckauf irreführend sein können. Ich ziehe es vor, einen einfach zu schreibenden und zu berechnenden Tiefpassfilter zu verwenden, um schnelle Transienten zu entfernen und einen vernünftigen Pseudo-Durchschnitt der letzten Ergebnisse anzuzeigen:
// 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);
Die „Halbwertszeit“ dieses Filters – die Anzahl der Frames, die benötigt wird, um sich vom alten Wert auf halbem Weg zu einem neuen, stabilen Wert zu bewegen – ist filterStrength*Math.log(2)
(ca. 70 % der Stärke).
Zum Beispiel eine Stärke von 20
bewegt sich auf halbem Weg zu einer sofortigen Änderung in 14 Frames, 3/4 des Weges dorthin in 28 Frames, 90 % des Weges dorthin in 46 Frames und 99 % des Weges dorthin in 92 Frames. Bei einem System, das mit etwa 30 fps läuft, wird eine plötzliche, drastische Leistungsänderung innerhalb einer halben Sekunde offensichtlich sein, aber Einzelbildanomalien werden immer noch „weggeworfen“, da sie den Wert nur um 5 % der Differenz verschieben.
Hier ist ein visueller Vergleich verschiedener Filterstärken für ein Spiel mit ~30 fps, das einen vorübergehenden Einbruch auf 10 fps und später eine Geschwindigkeit von bis zu 50 fps aufweist. Wie Sie sehen können, spiegeln niedrigere Filterwerte schneller „gute“ Änderungen wider, sind aber auch anfälliger für vorübergehende Schluckaufe:
Endlich, hier ist ein Beispiel den obigen Code zu verwenden, um tatsächlich eine ‘Spiel’-Schleife zu bewerten.
Sehr schöne Grafik! Wie hast du das gemacht?
– Benny Code
13. Februar 2013 um 23:12 Uhr
@BennyNeugebauer Das obige wurde in Excel erstellt, nur weil es für eine einmalige Sache etwas einfacher war als Verwenden von HTML5 Canvas für hübsche IIR-Grafiken.
– Phrogz
14. Februar 2013 um 3:42 Uhr
Gibt es einen Grund, warum ich unendliche fps erhalte, wenn ich den Anforderungsanimationsrahmen verwende? Ich verwende eine Filterstärke von 1 für die genauesten fps? passiert nur ab und zu (unendlich fps) : jsfiddle.net/CezarisLT/JDdjp/10
– Kivylios
17. Dezember 2013 um 22:23 Uhr
@CezarisLT Infinite FPS == ein Rückruf, der zur gleichen Zeit gemeldet wird (new Date
) wie beim vorherigen Aufruf. Sie können dies durch Kaution verhindern if (thisLoop==lastLoop)
. Beachten Sie jedoch, dass, wenn Sie eine Filterstärke von verwenden 1
, es macht überhaupt keinen Sinn, den Filter zu verwenden. Verwenden Sie einfach @SLaks Antwort.
– Phrogz
19. Dezember 2013 um 1:49 Uhr
@Phrogz Ich weiß, ich bin ein bisschen spät zur Party … aber selbst wenn ich Ihren vorgeschlagenen Schutz gegen den unendlichen FPS-Fehler verwende. Ich bekomme immer noch unendlich fps? irgendwelche Vorschläge?
– FutureCake
15. November 2017 um 22:47 Uhr
SLaks
In gameLoop
sehen Sie sich den Unterschied zwischen an new Date
Und new Date
aus der letzten Schleife (in einer Variablen speichern).
Mit anderen Worten:
var lastLoop = new Date();
function gameLoop() {
var thisLoop = new Date();
var fps = 1000 / (thisLoop - lastLoop);
lastLoop = thisLoop;
...
}
thisLoop - lastLoop
ist die Anzahl der Millisekunden, die zwischen den beiden Schleifen vergangen sind.
könntest du new Date durch Date.now() ersetzen, dasselbe, aber korrekter imo
– caub
10. August 2016 um 17:16 Uhr
Wie aktualisiere ich die Funktion gameLoop() in Abhängigkeit von den tatsächlichen fps? Denn bei Verwendung von setInterval() kann ich das Argument des Zeitintervalls nur einmal übergeben.
– Jacek Dziurdzikowski
25. Februar 2018 um 11:35 Uhr
@JacekDziurdzikowski: Anruf setTimeout()
jedes Mal, um den nächsten Rahmen zu planen.
– SLaks
25. Februar 2018 um 15:38 Uhr
@JacekDziurdzikowski Verwenden requestAnimationFrame
ist besser für die Leistung als beides zu verwenden setInterval()
oder setTimeout()
da es das Timing automatisch an die fps anpasst.
– Greyson R.
27. Juli 2019 um 23:49 Uhr
Wenn es nach mir ginge, würde ich aufgrund der Vorteile in Genauigkeit und Effizienz lieber so etwas wie performance.now anstelle von Datumsangaben verwenden
– AlphaHeul
12. November 2022 um 11:08 Uhr
NVRM
Meine 2 Cent:
Nützlich für mich, um Optimierungen zu vergleichen. Verbrennen Sie natürlich ein bisschen Ressourcen, nur zum Testen.
Im Idealfall sollte Ihre App-Bildrate bei voller Nutzung, bei Verwendung von Ereignissen, Schleifen usw. immer deutlich unter 50 ms pro Bild bleiben. Dies entspricht 20 FPS.
Das menschliche Auge fühlt sich unter 24 FPS verzögert, das ist 1000/24 = 41 ms
So, 41ms denn ein Rahmen ist das kleinste Zeitfenster, um die natürliche Fließfähigkeit zu erhalten. Höhere Werte sind zu vermeiden.
let be = Date.now(),fps=0,info='';
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;
info+=(''+new Date()+' '+fps+'\n');
}
)
<span id="kFps"></span>
<progress id="kpFps" value="0" min="0" max="100" style="vertical-align:middle"></progress>
<button onclick="try{console.clear();console.info(info)}catch{}">Statistics</button>
Nur eine Testschleife, um die Idee zu bekommen, 50-ms-Intervall, sollte reibungslos mithalten!
Sehen Sie den Fortschrittsbalken über dem Springen? ^
Das sind Frame-Verluste, die der Browser versucht, durch Opfer mitzuhalten, indem er zum nächsten Frame springt. Diese Spitzen sind zu vermeiden. Der nächste Ausschnitt verbrennt Ressourcen (dh FPS):
let t
for (let i=0;i<99999;i++){
t = setTimeout(function(){
console.log("I am burning your CPU! " + i)
clearTimeout
},50)
}
Neuere Versionen von Debuggern haben einen FPS-Zähler, in dem performance
Registerkarte, während der Aufnahme. Dies ist nicht perfekt, da es die Tests überlastet.
Wie wäre es mit AnfrageAnimationFrame?
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)
}
);
Damit berechne ich die 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');
}
}