Jak powiedziano tutaj :
Czas czas
Czas na początku tej ramki (tylko do odczytu). Jest to czas w sekundach od rozpoczęcia gry.
I jak wiem czas jest przechowywany w liczbach zmiennoprzecinkowych. Moje pytanie brzmi: co stanie się, gdy wartość czasu stanie się bardzo duża? Czy to może się przepełnić? Czy straci precyzję i spowoduje błędy? Czy gra po prostu się zawiesi czy co?
Odpowiedzi:
Istnieje rzeczywiste ryzyko utraty dokładności czasu przy użyciu pływaka o pojedynczej precyzji .
Nadal zachowa dokładność z dokładnością do sekundy przez 97 dni . Ale w grach często zależy nam na dokładności rzędu czasu trwania klatki.
Wartość pływalności pojedynczej precyzji w sekundach zaczyna tracić milisekundową dokładność po około 9 godzinach .
To już nie jest poza możliwością pojedynczej sesji gry lub pozostawienia gry z „AFK”, gdy jesteś w pracy / szkole lub śpisz. (Jest to jeden z powodów, dla których powszechnym sposobem testowania gry jest uruchamianie jej przez noc i sprawdzanie, czy nadal gra poprawnie rano)
Na nowoczesnych konsolach, w których gry są często zawieszane i wznawiane między sesjami gry, a nie zamykane całkowicie, nie jest niespodzianką, że „pojedyncza sesja” z perspektywy gry przekroczy 9 godzin czasu działania, nawet w krótkich seriach.
Zakładając, że jedność
deltaTime
jest obliczana zdeltaTime
dokładniejszego źródła czasu, co potwierdzają eksperymenty Petera w innej odpowiedzi, poleganie na taktowaniu w skali klatki jest względnie bezpieczne (po prostu zachowaj ostrożność przy sumowaniu bardzo długich czasów trwania przez zsumowaniedeltaTime
wartości - dodając małe przyrosty do Większy pływak to klasyczny przepis na utratę precyzji, nawet jeśli kompensujesz zręczne algorytmy ).Ponieważ
fixedDeltaTime
zachowuje tę samą wartość, którą ustawiłeś, zamiast dynamicznie zmieniać klatkę, możesz także ustawić zachowanie zależne od czasu w FixedUpdate, aby uzyskać silniejsze gwarancje spójności.deltaTime
automatycznie zwróci odpowiednią stałą różnicę w tych metodach. Chociaż pomiędzy aktualizacjami ustalonymi i ramkami może występować częstotliwość uderzeń, można to wygładzić poprzez interpolację .Czego chcesz uniknąć, obliczając czasy trwania, odejmując jeden znacznik czasu od drugiego . Po wielu godzinach gry może to spowodować katastrofalne anulowanie, co prowadzi do znacznie mniejszej precyzji niż na początku biegu. Jeśli porównywanie znaczników czasu jest ważne dla twojego systemu, możesz wygenerować własną wartość czasu w wyższej rozdzielczości przy użyciu innych metod, takich jak
System.Diagnostics.Stopwatch
zamiastTime.time
.źródło
Maksymalna wartość pływaka wynosi 3,40282347 * 10 ^ 38, co odpowiada 10 ^ 31 lat w przypadku pomiaru w sekundach (lub 10 ^ 28 lat w przypadku pomiaru w milisekundach). Zaufaj mi, to się nie przepełni.
Jedyne, co może się pojawić, to niedokładność. Ale liczba zmiennoprzecinkowa pojedynczej precyzji ma dokładność 7-8 cyfr dziesiętnych. Jeśli używasz go do pomiaru sekund, jest dokładny przez około 194 dni. Pomiar milisekund jest dokładny tylko przez 4,5 godziny. To zależy całkowicie od dokładności, której potrzebujesz, i być może będziesz musiał znaleźć alternatywne sposoby, jeśli chcesz być dokładny do milisekundy (czego prawdopodobnie nie).
źródło
Ile precyzji potrzebuje Twoja gra?
32-bitowa liczba zmiennoprzecinkowa ma 24 bity precyzji. Innymi słowy, w chwili t dokładność wynosi ± 2–23 × t. (To nie jest dokładnie poprawne, ale jest blisko, a dokładne szczegóły nie są strasznie interesujące.)
Jeśli potrzebujesz dokładności 1ms, to po 1ms ÷ 2 -23 = 8400 s = 2h 20m, liczba zmiennoprzecinkowa 32-bitowa jest już nie do przyjęcia. Precyzja 1 ms nie jest konieczna w większości gier, ale jest uważana za niezbędną w zastosowaniach muzycznych.
Jeśli twoja gra działa na monitorze 144 Hz, a chcesz grafiki z dokładnością do klatek, to po 1 ÷ 144 Hz ÷ 2 -23 = 58000 s = 16h 32-bitowa liczba zmiennoprzecinkowa nie jest już akceptowana. 16h to długi czas na uruchomienie gry, ale nie jest to niemożliwe. Założę się, że znaczny procent z nas prowadził grę przez 16 godzin w jednym odcinku - nawet jeśli tylko dlatego, że zostawiliśmy grę uruchomioną i przespaliśmy się. W tym momencie aktualizacje animacji i fizyki zostałyby zredukowane do poniżej 144 Hz.
Jeśli Unity's
Time.deltaTime
jest obliczany na podstawie zegara o wyższej precyzji, możesz go użyć i nadal uzyskać pełną precyzję. Nie wiem czy to prawda czy nie.Dygresja
Gry i inne programy w systemie Windows często wykorzystują
GetTickCount()
czas. Ponieważ używa 32-bitowej liczby całkowitej do zliczania milisekund, zawija się co około 50 dni, jeśli pozostawisz komputer na tak długo. Podejrzewam, że wiele gier zawiesiłoby się, zawiesiło lub źle działało w dziwny sposób, gdybyś grał w nie po 50 dniach.Liczby całkowite, takie jak Windows
GetTickCount()
, mają ryzyko przepełnienia, podczas gdy zmiennoprzecinkowe, podobnie jak UnityTime.time
, mogą stracić precyzję.źródło
Pozostałe odpowiedzi tylko spekulują, więc napisałem prosty projekt Unity i pozwoliłem mu działać przez chwilę. Po kilku godzinach jest to wynik:
UnityEngine.Time.time
dość szybko traci dokładność. Zgodnie z oczekiwaniami, po uruchomieniu gry przez 4 godziny wartości skaczą o 1 milisekundę, a następnie niedokładność wzrasta.UnityEngine.Time.deltaTime
zachowuje swoją początkową dokładność poniżej milisekund, nawet po kilku godzinach działania Unity. Jest więc praktycznie gwarantowane, żedeltaTime
pochodzi od zależnego od platformy licznika wysokiej rozdzielczości (który zwykle przepełnia się po 10-1000 latach). Istnieje niewielkie ryzyko, któredeltaTime
na niektórych platformach nadal straci precyzję.Niedokładność Czasu jest problemem wszystkiego, od czego zależy
UnityEngine.Time.time
. Jednym konkretnym przykładem jest rotacja (np. Wiatraka), na której zwykle opiera sięUnityEngine.Mathf.Sin(UnityEngine.Time.time*rotationSpeed)
. Jeszcze bardziej problem_Time
polega na jawnym używaniu animacji przez shadery. Jak wysoka musi być niedokładność, zanim zacznie być zauważalna? Dokładność 20-30 ms (2 dni) powinna być punktem, w którym zauważą ludzie, którzy są świadomi problemu i zwracają szczególną uwagę. Po 50-100 ms (5-10 dniach) wrażliwe osoby, które nie wiedzą o problemie, zaczną go rozgryzać. Od 200 do 300 ms (20-30 dni) problem będzie oczywisty.Do tej pory nie zostały przetestowane dokładność
_SinTime
,_CosTime
iUnity_DeltaTime
, więc nie mogę wypowiedzieć się na temat tych.To jest skrypt, którego użyłem do testowania. Jest on dołączony do
UI.Text
elementu, Ustawienia odtwarzacza projektu pozwalają na uruchomienie projektu w tle, a VSync w Ustawieniach jakości jest ustawiony na Co sekundę V Puste:Jeśli zastanawiasz się nad
0.033203
wartością, jestem pewien, że tak naprawdę0.033203125
ma binarną reprezentację zmiennoprzecinkową00111101000010000000000000000000
. Zwróć uwagę na wiele0
s w mantysie.Obejścia
Większość gatunków nie wymaga obejścia. Większość graczy nawet nie zagra w grę przez 100 godzin, więc inwestowanie pieniędzy w celu rozwiązania problemu, który ludzie zauważą dopiero po hipotetycznym kilku dniach ciągłego grania, jest ekonomicznie nieopłacalne. Niestety nie mogę wymyślić prostego, uniwersalnego obejścia, które naprawia cały problem bez istotnych wad.
źródło