Kann es schaden, die Hauptspielrunde unkontrolliert laufen zu lassen?

19

Ich habe mich gefragt, ob es einen möglichen Schaden gibt, wenn meine Spieleschleife so schnell läuft, wie es das System zulässt.

Ich habe derzeit eine Schleife, die durch Messen der verstrichenen Zeit in Nanosekunden die Spielelogik und die Renderlogik problemlos mit vordefinierten Geschwindigkeiten ausführt. Tatsächlich wird jede Logik, die ich in der Schleife tue, auf eine bestimmte Anzahl von Aufrufen pro Sekunde getaktet.

Die Schleife selbst läuft jedoch ungefähr so ​​schnell wie sie möchte, was auf meiner Maschine ungefähr 11,7 Millionen Schleifen pro Sekunde ergibt.

Schleife (einfacher Pseudocode):

while(!isGameOver){

 if(canPollInputs){
    pollInputs()
 }

 while(canStepLogic){
    stepLogic()
 }

 if(canRender){
    render()
 }
}

Meine Frage ist im Grunde, ob diese einfache Schleife, wenn sie nicht mit kontrollierter Geschwindigkeit läuft, einem System Schaden zufügen kann.

Bearbeiten: Das bedeutet, dass meine Logik 30-mal pro Sekunde (30 tps) ausgeführt wird, mein Renderer mit 60 fps ausgeführt wird, ich 100-mal pro Sekunde Eingaben abrufe und es gibt auch eine Logik, mit der Logik oder Rendern länger als erwartet fertig werden kann . Die Schleife selbst wird jedoch nicht gedrosselt.

Bearbeiten: Wenn Sie Thread.sleep()z. B. die Hauptschleife auf 250 Schleifen pro Sekunde drosseln, führt dies zu einer Reduzierung, aber die Schleifen laufen mit etwa 570 Schleifen pro Sekunde anstelle der gewünschten 250 (Code wird hinzugefügt, wenn ich mich auf meinem Desktop-Computer befinde.)

Edit: Los geht's, ein funktionierender Java-Gameloop, um die Dinge zu klären. Fühlen Sie sich auch frei, es zu benutzen, aber fordern Sie es nicht von Ihnen an;)

private void gameLoop() {

    // Time that must elapse before a new run
    double timePerPoll = 1000000000l / targetPPS;
    double timePerTick = 1000000000l / targetTPS;
    double timePerFrame = 1000000000l / targetFPS;
    int maxFrameSkip = (int) ( (1000000000l / MINIMUM_FPS) / timePerTick);

    int achievedPPS = 0;
    int achievedFPS = 0;
    int achievedTPS = 0;

    long timer = TimeUtils.getMillis();

    int loops = 0;

    int achievedLoops = 0;

    long currTime = 0l;
    long loopTime = 0l;

    long accumulatorPPS = 0l;
    long accumulatorTPS = 0l;
    long accumulatorFPS = 0l;

    long lastTime = TimeUtils.getNano();

    while(!isRequestedToStop) {
        currTime = TimeUtils.getNano();
        loopTime = currTime - lastTime;
        lastTime = currTime;

        loops = 0;

        accumulatorPPS += loopTime;
        accumulatorTPS += loopTime;
        accumulatorFPS += loopTime;

        if(accumulatorPPS >= timePerPoll) {
            pollInputs();
            playerLogic();
            achievedPPS++;
            accumulatorPPS -= timePerPoll;
        }

        while(accumulatorTPS >= timePerTick && loops < maxFrameSkip) {
            tick();
            achievedTPS++;
            accumulatorTPS -= timePerTick;
            loops++;
        }

        // Max 1 render per loop so player movement stays fluent
        if(accumulatorFPS >= timePerFrame) {
            render();
            achievedFPS++;
            accumulatorFPS -= timePerFrame;
        }

        if(TimeUtils.getDeltaMillis(timer) > 1000) {
            timer += 1000;
            logger.debug(achievedTPS + " TPS, " + achievedFPS + " FPS, "
                    + achievedPPS + " Polls, " + achievedLoops + " Loops");
            achievedTPS = 0;
            achievedFPS = 0;
            achievedLoops = 0;
        }

        achievedLoops++;
    }
}

Wie Sie sehen, wird fast kein Code in jeder Schleife ausgeführt, sondern immer eine bestimmte Auswahl, die davon abhängt, wie viel Echtzeit vergangen ist. Die Frage bezieht sich auf diese 'Worker-Schleife' und wie sie das System beeinflusst.

dot_Sp0T
quelle
2
obligatorischer link 'fix your timestep': gafferongames.com/game-physics/fix-your-timestep lies ihn bitte. Beachten Sie auch, dass Thread.Sleep () nicht verwendet werden kann, um den Zeitschritt zuverlässig zu drosseln, da das Betriebssystem nicht garantiert, dass die Steuerung nach der angeforderten Zeit an Ihre Anwendung zurückgegeben wird. (Es kann variieren).
Roy T.
Ja, das ist das Problem mit dem Pseudocode. Ich habe das meiste getan, worüber Gaffer schreibt (ich arbeite derzeit an einer Delta-Implementierung, die meine Schleifenstruktur ergänzt). Wenn ich Thread.sleep () nicht verwenden kann, was ist sonst noch in Standard-Java verfügbar?
dot_Sp0T
1
Normalerweise verwenden Sie eine Besetzt-Schleife mit Thread.Sleep (0) und hoffen auf das Beste. Gaffer spricht in einigen Artikeln viel darüber.
Roy T.
Nun, das ist im Grunde das, was ich getan habe, nur ohne thread.sleep (0), UND was ursprünglich diese Frage provoziert hat. Hat eine Busy-Schleife (bzw. keine Busy-Schleife, da selbst diese kleine Wiederholungslogik gedrosselt wird) für das System Schaden angerichtet?
dot_Sp0T
Vor einiger Zeit führte ein Fehler dazu, dass Starcraft II dies unter bestimmten Bedingungen tat. Es endete buchstäblich ein paar GPUs schmelzen. Also ja, es ist sehr wahrscheinlich, dass eine unkontrollierte Spielschleife Schaden anrichtet.
Mason Wheeler

Antworten:

35

Dadurch läuft ein CPU-Kern immer zu 100%. Dies schadet dem System normalerweise nicht . CPUs sind so ausgelegt, dass sie stundenlang zu 100% laufen. Bei einem mobilen Gerät wird der Akku jedoch schnell entladen und das Gerät aufgeheizt, was Sie wahrscheinlich etwa einen Stern in Ihrer Filialbewertung kosten wird. Auf einem Desktop-Computer ist dies weniger problematisch, verbraucht jedoch mehr Strom. Dadurch dreht sich der CPU-Lüfter schneller, was zu Geräuschen und zur Verschwendung von CPU-Zyklen führen kann, die ansonsten von anderen Prozessen verwendet werden könnten. Obwohl dies keine kritischen Mängel sind, handelt es sich dennoch um einen schlechten Stil. Sie sollten sie daher nach Möglichkeit vermeiden.

Sie haben nichts darüber gesagt, wie Ihre Spiellogik-Schleife intern funktioniert, aber wenn Sie den Delta-Zeit-Ansatz verwenden (jede Berechnung, die Sie durchführen, nimmt die Zeit seit dem letzten Aufruf in Betracht), haben Sie es mit sehr kleinen Delta-Werten zu tun. Zeitwerte. Dies bedeutet, dass Sie auf Probleme mit Gleitkommaungenauigkeiten stoßen können, die alle Arten von seltsamen Verhaltensweisen verursachen können. Außerdem ist die Auflösung des Systemtimers häufig begrenzt. Wenn Ihre Logikschleife zu schnell ist, können Sie einen Delta-t-Wert von Null erhalten, der dann eine Division durch Null verursachen kann, was zu einem Absturz führt.

Um dieses Problem zu mindern, sollten Sie Ihre Bildrate (Grafik und Logik) auf das Maximum dessen beschränken, was das menschliche Auge wahrnehmen kann. Wie viel umstritten ist, hängt von der Art der Animation und der Art der angezeigten Anzeige ab. Die Schätzungen reichen jedoch von 40 FPS bis 120 FPS. Das bedeutet, dass Sie für jede Schleife eine minimale Ausführungszeit zwischen 20 ms und 8 ms festlegen müssen. Sollte eine Schleifeniteration schneller beendet werden, lassen Sie den CPU-Thread sleepfür die verbleibende Zeitspanne.

Philipp
quelle
Danke für die Erklärung Philipp. Ich habe tatsächlich darauf hingewiesen, dass ich mit einer bestimmten Geschwindigkeit und einer bestimmten Geschwindigkeit laufe und das Polling nur einige Male pro Sekunde durchführe. Ich werde versuchen, es klarer zu machen.
dot_Sp0T
@ dot_Sp0T Nach der Bearbeitung Ihrer Frage sind nur der erste Absatz und der letzte Satz für Ihren Fall relevant. Ich möchte jedoch den zweiten und dritten Absatz meiner Antwort beibehalten, da sie für andere hilfreich sein könnten.
Philipp
Ich werde Ihre Antwort vermutlich genauso gut annehmen wie der erste Absatz eine Antwort gibt. Würde es Ihnen etwas ausmachen, sich optisch vom Rest der Antwort abzuheben?
dot_Sp0T
Spielen Sie eine nicht gepatchte Civilization 2 auf einem Desktop und Sie werden feststellen, dass dies ein Problem ist. Zumindest tue ich das. Achselzucken
CORSIKA
1
Zusätzlich zu den Überlegungen zu Akku und Lüfter kann eine erhöhte CPU-Auslastung zu Überhitzung führen, die unangenehm sein kann (z. B. Laptop, insbesondere rMBP) und sogar zum Herunterfahren des PCs führen kann (insbesondere bei älteren PCs mit staubigen Kühlern). Diese Faktoren sind ärgerlich, wenn Sie alle Kerne zu 100% ausführen .
NPSF3000
2

Sie verschwenden CPU-Zyklen. Das bedeutet geringere Akkulaufzeit bei Notebooks, Tablets und Handys, höhere Stromrechnungen, mehr Wärme, die von der Maschine erzeugt wird, lautere Lüfter. Außerdem kann es sein, dass Sie Zyklen von anderen wichtigen Systemprozessen essen (z. B. kann der Windows-Server ruckeln), was sich dann auf das Gameplay auswirken kann. Einige System-Scheduler in den heutigen vorbeugenden Multitasking-Systemen bestrafen auch Anwendungen, die zu viele Zyklen benötigen. Daher sind Sie möglicherweise zuerst schnell und können plötzlich seltsame Ruckler feststellen, wenn Sie vom System gedrosselt werden.

Viele Hardcore-Gamer bauen auch benutzerdefinierte PCs von Grund auf neu, die den Spezifikationen ihrer Fans entsprechen. In diesem Fall kann ein heißer Tag und die Hitze, die Ihr Spiel erzeugt, dazu führen, dass die Sicherheit in der Maschine ausgelöst wird (bestenfalls) oder dass Teile überhitzt und beschädigt werden sterben (im schlimmsten Fall). Wenn es sich also um Ihre Zielgruppe handelt, möchten Sie vielleicht sicherstellen, dass Sie immer ein wenig Platz "oben" lassen.

Schließlich gibt es Spielprobleme, bei denen Sie möglicherweise Spieler mit schnelleren Maschinen gegenüber denen mit langsameren bevorzugen. Wenn die Spielschleife auf eine bestimmte Frequenz begrenzt ist und zusätzliche Zyklen nur für nicht spielrelevante Aspekte (wie das Rendern von Grafiken mit höherer Wiedergabetreue, Surround-Sound-Effekten oder was auch immer) verwendet werden, wird Ihr Spiel fairer.

Geschicklichkeit
quelle
Ich würde umgekehrt sagen, dass Leute, die leidenschaftlich ihre Maschinen bauen, gute Ventilatoren verwenden, sogar Wasserkühlung. Nur HTPC- oder Mini-ITX-Fälle können Einschränkungen für diesen Teil haben. Ansonsten werden arme, aber begeisterte Menschen das Box-Ventirad nutzen. das reicht schon bei 100%, heiß aber ok.
v.oddou
Ich wiederhole nur aus Erfahrung. Wenn Sie sich Star Trek Online ansehen, haben sie tatsächlich eine separate Einstellung in ihrer GUI, die sleep () s in ihre Hauptschleife einfügt, um zu verhindern, dass bestimmte Maschinen überhitzt werden. Es kann also keine ungewöhnliche Sache sein, wenn der Hersteller von Neverwinter und STO sah die Notwendigkeit, es hinzuzufügen. Denken Sie an diese Leidenschaft! = Geschicklichkeit. Es gibt viele geschickte und leidenschaftliche Bastler, aber es gibt auch Anfänger und andere, die noch lernen, und mit einer anständigen Abbrecherquote sagen Statistiken, dass sie die Mehrheit sind.
uliwitness
Dank dieser Kommentare habe ich Ihre Antwort erneut gelesen. Sie geben gültige Punkte an, sprechen die Frage aber leider nicht mit der Kontroverse zwischen schnelleren und langsameren Maschinen an . Die Logikschleife ( in Ihrem dritten Absatz Gameloop genannt ) ist begrenzt. Die Frage war, wie man die Backbone-Schleife abdeckt, die einfach jeden Durchlauf neu bewertet, wenn Eingaben abgerufen, Logik berechnet oder ein Frame gerendert werden soll - also keine schnellere Logik, es sei denn, Ihre Maschine ist schrecklich lahm
dot_Sp0T
1

Du solltest keine nervösen Bewegungen / Spielabläufe haben

Es gibt zwei Möglichkeiten, wie Sie die Spiellogik implementieren können - in Echtzeit oder in Abhängigkeit von der Anzahl der "Runden" / Verarbeitungsschritte. Wenn sich ein Element in Ihrem Spiel nach links bewegt, ist die Bewegung dann anders, wenn Ihre stepLogic () 100 statt 50-mal aufgerufen wurde?

Wenn Ihr Code die verstrichene Zeit überall explizit behandelt und korrekt ausführt, ist dies möglicherweise in Ordnung. Wenn Ihr Code jedoch etwas enthält, das von der Anzahl der Schritte abhängt, treten unerwünschte Nebenwirkungen auf.

Erstens variiert die Geschwindigkeit von Dingen, die sich ständig bewegen sollten, unvorhersehbar (abhängig von der Prozessorauslastung), und dies führt zu sehr ärgerlichen Kontrollen - Sie können keinen präzisen Schlag oder Sprung ausführen, wenn das Spiel plötzlich schneller oder langsamer wird. Selbst bei Spielen ohne "Zucken" sieht es nervig und nervös aus, wenn sich die Dinge nicht reibungslos bewegen.

Zweitens kann es je nach Computergeschwindigkeit zu Problemen mit den Charakterfähigkeiten kommen - ein klassisches Beispiel ist das alte Quake-Problem, bei dem die maximale Sprungreichweite unbeabsichtigt von Ihren FPS abhing.

Diese Probleme können auch dann auftreten, wenn Sie versuchen, den Code fps-unabhängig zu machen. Die Anhäufung von Rundungsfehlern kann häufig zu solchen Fehlern führen.

Peter ist
quelle
1
So sehr ich Ihre Antwort mag, ist sie für die Frage nicht relevant, da ich nicht nach nervöser Bewegung / Spielweise frage, sondern nach dem Schaden, den eine unkontrollierte Schleife (die keine Logik, kein Rendering oder etwas anderes kontrolliert) dem System zufügen kann
dot_Sp0T
1

Der einzige potenzielle Schaden ist der Stromverbrauch. Tun Sie dies also nicht auf Mobilgeräten. Umgekehrt verbringen viele eingebettete Systeme ihr ganzes Leben in einer Schleife und warten darauf, dass etwas passiert.

Früher war es ganz normal, Game-Frames einfach so schnell wie möglich zu rendern, manchmal sogar ohne Timer, um das Gameplay für unterschiedliche CPU-Geschwindigkeiten auszugleichen. Das Rennspiel von Bullfrog, Hi-Octane, war ein besonders schlimmes Opfer, und ich vermute, das ist es, worauf sich das Plakat mit Civ2 bezieht.

Ich empfehle Ihnen, die Eingaben bei jedem Durchlauf mindestens abzufragen, wenn Sie sich auf einem Windows-System oder einem ähnlichen System befinden, um eine schnelle Eingabeantwort zu gewährleisten.

pjc50
quelle
Es ist keine Frage des Timers, es ist eine Frage eines Chronometers oder eines Leistungsindikators. Irgendwann muss man die Echtzeit bekommen, und eine freie Schleife funktioniert einwandfrei. Ein Timer (im Sinne einer regelmäßigen Unterbrechung) versucht jedoch, die Schleifengeschwindigkeit im allgemeinen Gebrauch zu regulieren. Das finde ich nicht gut. Es ist vorzuziehen, die swap/ present/ flip-Funktion zu verwenden, um die Spielschleife zu regulieren.
v.oddou