Ich hatte einige kleinere Frame-Drop-Probleme in einem 2D-XNA-Spiel.
Zunächst bin ich ein vsync'ed, gemischter Zeitschritt. Das ist:
IsFixedTimestep = false;
graphicsDeviceManager.SynchronizeWithVerticalRetrace = true;
Dies wird mit einem festen Physik-Zeitschritt von 120 Hz kombiniert, der mit dem in Fix Your Timestep! um nervöse Physikbewegungen zu vermeiden. Das Update wird also mit einem variablen Zeitschritt ausgeführt, und ein weiterer Tick wird mit einem festen Zeitschritt ausgeführt (die Idee stammt von Unitys Update / FixedUpdate).
Wenn sich ein Sprite mit gleichmäßiger Geschwindigkeit über den Bildschirm bewegt, fällt alle paar Sekunden ein Jitter / Schluckauf auf. Ein bisschen googeln hat mich vor einigen Jahren zu diesem Forumsbeitrag geführt, in dem ich über das gleiche Thema sprach.
Um dies zu testen, habe ich diesen Code einer Update-Methode hinzugefügt:
if(gameTime.ElapsedGameTime.TotalMilliseconds > 22)
{
Logger.Log(gameTime.ElapsedGameTime.TotalMilliseconds.ToString());
}
Sicher genug, alle paar Sekunden zeigte das Protokoll eine Zeit über 30 Millisekunden, normalerweise um 32. Da ein Frame mit 60 fps 16,6 Millisekunden entspricht, scheint ein Frame einfach verloren zu gehen. Ich habe zusätzlichen Code hinzugefügt, um den Bildschirm in diesem Fall rot zu blinken. Wiederum stelle ich sicher fest, dass die Kugel schluckt, wenn der Bildschirm rot blinkt. Wenn ein Frame einfach fallen gelassen wird, bedeutet dies, dass die Kugel stillsteht. Wenn der Frame schließlich ausgeführt wird, wird die Physik viermal ausgeführt (da sie doppelt so schnell wie der Monitor läuft, über zwei Frames) und die Kugel a bewegt Menge.
Jetzt bin ich mir nicht sicher, ob ich das beheben kann. Wenn dies tatsächlich eine Eigenart von XNA (und Gamedev im Allgemeinen?) Ist, kann der Frame-Drop unvermeidbar sein. Ich würde also entweder wissen, wie man den Frame-Drop entweder beseitigt oder wie sichtbar er ist. Noch ein paar Punkte:
1. Es ist wahrscheinlich nicht der GC.
In diesem Forumsbeitrag schienen sie das Problem bis zu einem Punkt zu verbessern, an dem der GC niemals / kaum laufen würde, und sahen das Problem immer noch. Um mich selbst zu überprüfen, habe ich einen Code hinzugefügt, der GC.GetTotalMemory(false)
jeden Frame überprüft. Wenn er aus dem letzten Frame entfernt wurde, protokollieren Sie "GC". Ich denke, ein Rückgang würde eine GC-Sammlung anzeigen, aber ich könnte mich irren. "GC" wurde unabhängig vom anderen Protokoll protokolliert, als ein Frame gelöscht wurde.
2. Ich kann keinen variablen Zeitschritt verwenden
Ich brauche die Physik, um über ein Netzwerk reproduzierbar zu sein. Dies bedeutet, dass es so deterministisch wie möglich sein muss (es spielt eigentlich keine 100% ige Rolle, aber es verursacht wahrnehmbare Artefakte, je weniger deterministisch es ist). Ich kann also nicht einfach die Geschwindigkeit von Objekten mit multiplizieren gameTime.ElapsedGameTime
.
3. Ich möchte IsFixedTimeStep nicht verwenden
Ich mag es, die Framerate ein bisschen unter meiner Kontrolle zu halten. Es gibt mehr Kontrolle über das Zeichnen und ermöglicht mehrere etwas unabhängige Frameraten. In dem Forumsbeitrag wurde auch angegeben, dass das Setzen von IsFixedTimeStep auf false das Problem behoben hat. Zugegeben, ich habe IsFixedTimeStep im Grunde selbst neu implementiert!
Außerdem IsFixedTimeStep = true;
hilft die Einstellung nicht beim Stottern.
4. Einige Ideen?
Wenn ich das Problem nicht beheben kann, kann ich es vielleicht irgendwie abmildern. Einige Ideen, die ich hatte, sind:
- Bewegungsunschärfe
- Geben Sie den Kugeln Spuren
- Erhöhen Sie das "Rauschen" auf dem Bildschirm, sodass ein Bildverlust ein kleines Problem darstellt
- Separates Update und Zeichnen in separate Threads?
- Mit Reißen und Unsynchronisieren von der vertikalen Rückverfolgung umgehen? Dies löst das Problem fast vollständig, aber die GPU-Nutzung geht zu 100%, da sie so schnell wie möglich aktualisiert und gezeichnet wird.
Vielleicht ist seit dem Forumsbeitrag 2008 auch etwas mit XNA passiert, das ich nutzen kann. Ansonsten bin ich mir nicht sicher, was ich gegen das Problem tun soll. Ist es ein wirklich kleines Problem? Ja! Ich würde aber gerne ein seidenweiches Spiel haben. Ich würde alle Ideen lieben!
quelle
Antworten:
Zu Beginn gibt es hier einen guten Beitrag von Shawn Hargreaves auf GameTime (genauer gesagt, fester und nicht festgelegter Zeitschritt) . Vielleicht gibt es Ihnen eine Idee oder einige Dinge zu versuchen.
Ich bin mir jedoch nicht ganz sicher, ob Sie den Garbage Collector ausschließen können.
Für Müll:
Führen Sie Ihr Spiel über CLR Profiler aus und sehen Sie, was es Ihnen sagt. Wenn Sie Zugriff auf eine Xbox 360 haben, können Sie mithilfe des XNA Remote Performance Monitor schneller feststellen, ob ein Problem vorliegt (im Gegensatz zu CLR Profiler wird Ihnen jedoch nicht mitgeteilt, wo das Problem liegt). Es gibt eine Reihe von Blog-Posts von Shawn über die Verwendung von XNA RPM hier und hier.
Auch Ihre Methode der Überprüfung Müll sollte funktionieren. Mein persönlicher Lieblingsweg ist jedoch ungefähr so:
Dann in Ihrem Update:
Hier erfahren Sie, wann eine Sammlung stattfindet, da diese WeakReference mit jeder Sammlung gesammelt wird, die ausgeführt wird. Wenn es dann gesammelt wurde, erhöhen wir unseren Zähler und setzen ihn zurück.
Allgemein:
Einige Frame-Sprünge sind unvermeidlich. Manchmal dauert ein Update oder (seltener) ein Draw länger als es sollte, und es gibt keine gute Möglichkeit, sich darauf einzustellen (genauer gesagt, keine gute einfache Möglichkeit, sich darauf einzustellen). Auf den ersten Blick möchten Sie vielleicht gameTime.IsRunningSlowly auf Verzögerungen überprüfen. Wenn XNA nicht glaubt, dass es langsam läuft, ist es höchstwahrscheinlich ein Problem mit der Aktualisierungsrate.
Hoffentlich hilft das!
quelle
Zum Thema Verwendung von DirectX / DXGI / XNA- und .NET-Sprachen - Wenn Ihre Anwendung den DirectX / .NET-Mustern und -Praktiken entspricht, wird die Garbage Collection Ihren Frame nicht beeinträchtigen. Sofern Ihre Anwendung in einem anderen Thread nichts Dummes tut oder Sie eine große Anzahl von Objekten in einer engen Schleife ohne ordnungsgemäße Entsorgung erstellen, ist dies 9/10 Mal ein Problem mit der Hauptschleifenlogik (Rundungsfehler sind häufig) oder mit dem Rendern Code.
quelle