wake-up-neo.com

Steady_Clock überspringt zwischen Aktualisierungen in der Hauptspielschleife

Beim Versuch, eine solide Spielschleife in SFML zu erarbeiten, bin ich auf dieses Problem gestoßen, das ich scheinbar nicht herausfinden kann. Ich konnte den gesamten SFML-Code entfernen und trotzdem das Problem mit clock() in time.h sehen. Dann ging ich weiter und sehe immer noch das Problem mit std::chrono::steady_clock.

Das Problem: Etwas konsistent sehe ich, wie viel Arbeit zwischen den Updates erledigt werden kann. Jedes Update sollte 1/60stel Sekunde dauern, und der Rest der Zeit wird in Draw() verbracht, um so viel Zeichnung wie möglich zu machen .. Manchmal ist die Anzahl der Draws ohne ersichtlichen Grund auf 0 oder 1 gesunken. Dies sprudelt bis zur tatsächlichen Anwendung in Form von merklichem Stottern. Abgesehen von den "Sprüngen" ist die Anzahl der durchgeführten Ziehungen sehr konstant.

Hier ist ein Bild (Beachten Sie den Sprung in der Aktualisierungszeit und die Anzahl der Draws): Konsolenausgabe des Problems

Etwas code:

#include <iostream>
#include <time.h>
#include <chrono>

using namespace std;
using namespace std::chrono;

void Draw()
{
    //for (int i = 0; i < 1000000; i++);
}

int main()
{
    steady_clock::time_point update_time;
    steady_clock::time_point update_next;
    int update_rate = 16666666; // 60 times a second (nanosecs)
    int updates;
    int max_updates = 5;
    int draws = 0;
    update_next = steady_clock::now();

    while (true)
    {
        updates = 0;
        update_time = steady_clock::now();
        while (duration_cast<nanoseconds>(update_time - update_next) > nanoseconds(update_rate) && updates++ < max_updates)
        {
            if (draws <= 1) {
                cout << "!!!!!!!!!!!!!ERROR!!!!!!!!!!!!!" << endl;
            }
            cout << "UPDATE - ";
            cout << "Draws: " << draws 
                 << " - UT - UN: " << duration_cast<nanoseconds>(update_time - update_next).count()
                 << endl;

            draws = 0;
            update_next += nanoseconds(update_rate);
        }
        draws++;
        Draw();
    }

    return 0;
}
  • Vielleicht verstehe ich etwas nicht über typische Anwendungen? Muss Windows regelmäßig CPU-Zyklen entführen?
  • Ich habe dieses Problem mit steady_clock, clock und in einer ausführlichen SFML-App gesehen, in der während Update und Draw gearbeitet wird
  • Ich gehe davon aus, dass die SFML-Uhr wahrscheinlich die Uhr time.h verwendet
  • Bei meinem Test haben die Prüfungen von max_updates nichts mit diesem Problem zu tun (ich glaube nicht, dass sie das Problem verursachen).

Die Tatsache, dass ich dies mit ein paar verschiedenen Timern gesehen habe, lässt mich glauben, dass mit meiner Implementierung oder meinem System etwas nicht stimmt. Dieses Beispiel wurde in VS ausgeführt, aber ich habe es auch in einem Standalone-Release exe gesehen. Wenn Sie mit der Aktualisierungsrate oder der Menge an Arbeit arbeiten, die in Draw ausgeführt wird, kann dies dazu beitragen, dass Sie für Sie angezeigt werden.


Nachdem ich meine Hintergrundprozesse getestet hatte, bemerkte ich einen merkwürdigen Zusammenhang. Dieses Überspringproblem tritt nur auf, wenn der Spotify-Web-Player in Chrome geöffnet ist und einmal pro Sekunde auftritt.

Ich habe diesen Beitrag gefunden, der möglicherweise in Verbindung steht: https://community.spotify.com/t5/Other-Partners-Web-Player-etc/Web-Player-on-Chrome-causes-lag-stutter/ td-p/4587103

11
S. Turnage

Vielleicht verstehe ich etwas nicht über typische Anwendungen? Muss Windows regelmäßig CPU-Zyklen entführen?

Ja absolut. Windows führt viele Prozesse gleichzeitig aus. Jetzt kommt Ihre Anwendung und führt eine im Wesentlichen belebte Spin-Loop aus. Irgendwann wird das Betriebssystem diese Priorität wahrscheinlich länger als erwartet zurücknehmen, da es nur nach einer langen Berechnung aussieht, und das Betriebssystem muss anderen Prozessen einen angemessenen Anteil an der CPU-Zeit einräumen.

Im Allgemeinen sollten Sie sich nicht darauf verlassen, dass Ihre Zeichenroutine eine genaue Anzahl von Malen pro Sekunde aufgerufen wird, und die Hauptuhr Ihres Spiels sollte mit übersprungenen Bildern umgehen können. Ich bin nicht mit SFML vertraut, daher kann ich dazu nichts sagen.

Ich habe jedoch Erfahrung mit Echtzeit-Audio (und Video für diese Angelegenheit), das in Schleifen ausgeführt wird, die 1000 Updates pro Sekunde überschreiten. Sie können den Zeitanteil der Spielschleife verbessern, indem Sie die Thread-Priorität auf THREAD_PRIORITY_HIGHEST oder THREAD_PRIORITY_TIME_CRITICAL setzen (siehe SetThreadPriority ).

Damit dies effektiv ist, sollten Sie auch eine gutmütige Anwendung sein und regelmäßig eine Art Wartezeit ausführen. Warten ermöglicht dem Betriebssystem, seine notwendigen Aufgaben zu erledigen, um andere Prozesse zu bedienen (von denen einige auch eine hohe Priorität haben und oft höher sind, als Sie als Benutzerraumanwendung erzwingen können).

Der naheliegende Ort für ein Warten ist vor Ihrem nächsten Ziehzyklus. Anstatt Ihren Timer mit 100% Kernauslastung zu drehen, berechnen Sie einfach, wie lange Sie warten möchten, und rufen Sie std::this_thread::sleep_for auf. Denken Sie daran, dass die einzige Garantie dafür ist, dass der Schlaf für mindestens den von Ihnen festgelegten Betrag gilt. Es kann und wird absolut mehr sein. Aber ich empfehle Ihnen, dort zu beginnen und einige Experimente durchzuführen.

8
paddy

Zusätzlich zu der Antwort von @ paddy empfehle ich, in feste Zeitschritte nachzuschauen. Wenn sich die Implementierung nicht lohnt, sollten Sie auch beachten, dass SFML Window.setFramerateLimit() hat. Es ist nicht sehr präzise, ​​aber die meisten einfachen Spiele benötigen keine große Präzision.

3
bruglesco

Ich habe Drehschleife plus Ertrag für 1 KHz Regelkreise mit guten Ergebnissen verwendet, erwarte jedoch einen Fristenschluss (einmal in tausend Zyklen auch lange Schlafzeiten).

1
PeppeDx

Ursprünglich sah es so aus, als wäre das Problem von meinem Antivirus verursacht worden, aber ich glaube, ich habe es eingegrenzt, um zu erkennen, ob der Webplayer offen ist und eine Leistungssteigerung von 1/Sek. Ich bin nicht sicher, warum das so wäre.

0
S. Turnage