Wie hier gesagt wird :
Zeit Zeit
Die Zeit am Anfang dieses Frames (schreibgeschützt). Dies ist die Zeit in Sekunden seit dem Start des Spiels.
Und wie ich weiß, ist die Zeit in float gespeichert. Meine Frage ist also, was passiert, wenn der Wert der Zeit sehr groß wird? Kann es überlaufen? Wird es an Präzision verlieren und Fehler verursachen? Wird das Spiel einfach abstürzen oder was?
Antworten:
Bei Verwendung eines Schwimmers mit einfacher Genauigkeit besteht die Gefahr eines Zeitverlusts .
Die Genauigkeit bleibt 97 Tage lang auf die nächste Sekunde genau . Aber in Spielen ist uns oft die Genauigkeit in der Größenordnung einer Frame-Dauer wichtig.
Ein Gleitzeitwert mit einfacher Genauigkeit in Sekunden beginnt nach etwa 9 Stunden an Millisekundengenauigkeit zu verlieren .
Dies ist bereits jetzt nicht mehr möglich, wenn Sie nur eine einzige Sitzung spielen oder das Spiel "AFK" laufen lassen, während Sie in der Arbeit / Schule sind oder schlafen. (Dies ist einer der Gründe, warum ein Spiel häufig über Nacht getestet wird, indem überprüft wird, ob es morgens noch korrekt abgespielt wird.)
Auf modernen Konsolen, auf denen Spiele häufig zwischen den Spielsitzungen angehalten und fortgesetzt werden, anstatt vollständig herunterzufahren, ist es aus Sicht des Spiels nicht unvorhergesehen, dass eine "einzelne Sitzung" 9 Stunden Laufzeit überschreitet, selbst wenn sie in kurzen Serien gespielt wird.
Unter der Annahme, dass
deltaTime
Unitys aus einer Zeitquelle mit höherer Genauigkeit berechnet wird, was in Peters Experimenten in einer anderen Antwort bestätigt wird,deltaTime
ist es relativ sicher , sich auf Frame-Scale-Timings zu stützen (seien Sie nur vorsichtig, wenn Sie sehr lange Zeiträume durch Summieren vondeltaTime
Werten akkumulieren - indem Sie kleine Inkremente hinzufügen Ein größerer Schwimmer ist ein klassisches Rezept für Präzisionsverluste, auch wenn Sie dies mit ausgeklügelten Algorithmen kompensieren .Da
fixedDeltaTime
der von Ihnen festgelegte Wert beibehalten wird, anstatt sich dynamisch von Frame zu Frame zu ändern, können Sie auch zeitabhängiges Verhalten in FixedUpdate festlegen, um stärkere Garantien für die Konsistenz zu erhalten.deltaTime
gibt bei diesen Methoden automatisch das entsprechende feste Delta zurück. Zwar kann es eine Taktfrequenz zwischen festen und Frame-Aktualisierungen geben, Sie können dies jedoch durch Interpolation ausgleichen .Was Sie vermeiden möchten, ist die Berechnung der Dauer durch Subtrahieren eines Zeitstempels von einem anderen . Nach stundenlangem Spielen kann dies zu einem katastrophalen Abbruch führen, was zu einer weitaus geringeren Präzision führt, als Sie es zu Beginn des Laufs erreichen. Wenn der Vergleich von Zeitstempeln für Ihre Systeme wichtig ist, können Sie Ihren eigenen Zeitwert mit höherer Auflösung mithilfe anderer Methoden wie
System.Diagnostics.Stopwatch
anstelle von generierenTime.time
.quelle
Der maximale Wert von float ist 3.40282347 * 10 ^ 38, was 10 ^ 31 Jahren entspricht, gemessen in Sekunden (oder 10 ^ 28 Jahren, gemessen in Millisekunden). Vertrauen Sie mir, es wird nicht überlaufen.
Das einzige, was auftauchen kann, ist Ungenauigkeit. Eine Gleitkommazahl mit einfacher Genauigkeit hat jedoch eine Genauigkeit von 7-8 Dezimalstellen. Wenn Sie es zum Messen von Sekunden verwenden, ist es ungefähr 194 Tage lang genau. Wenn Millisekunden gemessen werden, ist die Genauigkeit nur 4,5 Stunden lang. Es hängt also ganz von der Genauigkeit ab, die Sie benötigen, und Sie müssen möglicherweise alternative Wege finden, um auf die Millisekunde genau zu sein (was Sie wahrscheinlich nicht tun).
quelle
Wie viel Präzision braucht dein Spiel?
Ein 32-Bit-Float hat eine Genauigkeit von 24 Bit. Mit anderen Worten, zum Zeitpunkt t beträgt die Genauigkeit ± 2 - 23 × t. (Dies ist nicht genau richtig, aber es ist nah, und die genauen Details sind nicht besonders interessant.)
Wenn Sie eine Genauigkeit von 1 ms benötigen , ist ein 32-Bit-Float nach 1 ms s 2 -23 = 8400 s = 2h 20m nicht mehr akzeptabel. Eine Genauigkeit von 1 ms ist für die meisten Spiele nicht erforderlich, wird jedoch für Musikanwendungen als erforderlich angesehen.
Wenn Ihr Spiel läuft auf einem 144 Hz - Monitor, und Sie framegenaue Grafiken wollen, dann nach 1 ÷ 144 Hz ÷ 2 -23 = 58000 s = 16h, ein 32-Bit - Float nicht mehr akzeptabel ist . 16h ist eine lange Zeit, um ein Spiel zu starten, aber es ist nicht unvorstellbar. Ich wette, ein signifikanter Prozentsatz von uns hat 16 Stunden lang ein Spiel in einem Durchgang gespielt - auch wenn wir nur das Spiel verlassen haben und etwas geschlafen haben. Zu diesem Zeitpunkt würden Animationen und Aktualisierungen der Physik auf unter 144 Hz reduziert.
Wenn Unity
Time.deltaTime
aus einer Uhr mit höherer Genauigkeit berechnet wird, können Sie diese verwenden und trotzdem die volle Genauigkeit erhalten. Ich weiß nicht, ob das stimmt oder nicht.Randnotiz
Spiele und andere Programme unter Windows ermitteln häufig
GetTickCount()
die Uhrzeit. Da für die Zählung von Millisekunden eine 32-Bit-Ganzzahl verwendet wird, wird etwa alle 50 Tage ein Zeilenumbruch durchgeführt, wenn Sie Ihren Computer so lange eingeschaltet lassen. Ich vermute, dass sich viele Spiele auf bizarre Weise aufhängen, abstürzen oder schlecht benehmen würden, wenn Sie sie an der 50-Tage-Marke spielen würden.Ganzzahlen wie bei Windows
GetTickCount()
können überlaufen, während bei Floats wie bei Unity dieTime.time
Gefahr besteht, dass sie an Genauigkeit verlieren.quelle
Die anderen Antworten spekulieren nur, deshalb habe ich ein einfaches Unity-Projekt geschrieben und es eine Weile laufen lassen. Nach ein paar Stunden ist dies das Ergebnis:
UnityEngine.Time.time
verliert ziemlich schnell an Genauigkeit. Wie erwartet, springen die Werte nach 4-stündigem Ausführen des Spiels um 1 Millisekunde, und die Ungenauigkeit nimmt danach zu.UnityEngine.Time.deltaTime
behält seine anfängliche Genauigkeit von unter einer Millisekunde, selbst nachdem Unity stundenlang ausgeführt wurde. Somit ist praktisch garantiert, dassdeltaTime
von einem plattformabhängigen hochauflösenden Zähler (der in der Regel nach 10-1000 Jahren überläuft) abgeleitet wird. Es bleibt ein winziges Risiko,deltaTime
das auf einigen Plattformen immer noch an Präzision verliert.Die Ungenauigkeit der Zeit ist ein Problem für alles, worauf es ankommt
UnityEngine.Time.time
. Ein konkretes Beispiel ist die Rotation (z. B. einer Windmühle), auf der in der Regel basiertUnityEngine.Mathf.Sin(UnityEngine.Time.time*rotationSpeed)
. Ein noch größeres Problem wird_Time
explizit für Animationen von Shadern verwendet. Wie hoch muss die Ungenauigkeit sein, bevor sie spürbar wird? Die Genauigkeit von 20-30 ms (2 Tage) sollte der Punkt sein, an dem Personen, die sich des Problems bewusst sind und genau darauf achten, es bemerken werden. Bei 50-100 ms (5-10 Tage) werden sensible Leute, die nicht über das Problem Bescheid wissen, anfangen, es herauszufinden. Ab 200-300 ms (20-30 Tage) ist das Problem offensichtlich.Bisher habe ich die Genauigkeit von
_SinTime
,_CosTime
und noch nicht getestetUnity_DeltaTime
, daher kann ich dazu noch keinen Kommentar abgeben.Dies ist das Skript, das ich zum Testen verwendet habe. Es ist an ein
UI.Text
Element angehängt . In den Player-Einstellungen des Projekts kann das Projekt im Hintergrund ausgeführt werden. In den Qualitätseinstellungen ist VSync auf Every Second V Blank festgelegt:Wenn Sie sich über den
0.033203
Wert wundern , bin ich mir ziemlich sicher, dass dies tatsächlich der Fall ist0.033203125
, für den eine binäre Gleitkommadarstellung vorliegt00111101000010000000000000000000
. Beachten Sie die vielen0
s in der Mantisse.Problemumgehungen
Die meisten Genres benötigen keine Problemumgehung. Die meisten Spieler werden nicht einmal 100 Stunden lang ein Spiel spielen, weshalb es wirtschaftlich nicht rentabel ist, Geld zu investieren, um ein Problem zu beheben. Leider kann ich keine einfache, universelle Problemumgehung finden, die das gesamte Problem behebt, ohne einige wesentliche Nachteile mit sich zu bringen.
quelle