Unity'de Time.time çok büyüdüğünde ne olur?


37

Deniyor gibi burada :

Zaman zaman

Bu çerçevenin başındaki saat (Salt Okunur). Oyunun başlamasından bu yana saniye cinsinden zaman.

Ve bildiğim gibi zaman floatta saklanır. Öyleyse benim sorum şu ki, zamanın değeri çok büyüdüğünde ne olacak? Taşabilir mi? Hassasiyetini kaybedecek ve böceklere neden olacak mı? Oyun sadece çökecek mi?



5
@AlexandreVaillancourt Burada "Time.time çok büyüdüğünde sorunlar var mı?" Olarak yorumlamamızın yararlı bir sorusu olduğunu düşünüyorum. Kelimenin tam anlamıyla sadece "taşma" odaklanmak yerine. Geri bildiriminizi ele almak için soruyu bu satırlar boyunca düzenledim.
DMGregory

2
@DMGregory Ancak soru zaten cevaplandı ve kabul edildi ... Düzenlemelerinizin daha faydalı bir soru için biraz geç kalmasına katılıyorum.
MichaelHouse

Düzenlemeyi ifade etmeye çalıştım, böylece kabul edilen cevap hala düzenlenen sürüm için doğru bir cevap olacak. (Sonuçta, zaten hassas meselelerden bahsediyor.) Yine de geri alındığı takdirde kırılmam.
DMGregory

Yanıtlar:


62

Tek duyarlıklı bir şamandıra kullanımından kaynaklanan zaman doğruluğu kaybı riski vardır .

97 gün boyunca en yakın saniyeye kadar hassasiyetini koruyacaktır . Ancak oyunlarda genellikle bir kare süresi sırasındaki doğruluğu önemsiyoruz.

Saniye cinsinden tek bir hassas yüzdürme süresi, yaklaşık 9 saat sonra milisaniye doğruluğunu kaybetmeye başlar .

Bu zaten, tek bir oyun oturumu için veya iş / okuldayken veya uyurken oyunun "AFK" ile çalışmasına izin verme ihtimalinin dışında değil. (Bu, bir oyunu test etmenin yaygın bir yolunun bir gecede çalıştırılması ve hala sabahları doğru şekilde oynamasını kontrol etmesinin bir nedenidir).

Oyunların tamamen kapatılmasından ziyade oyun oturumları arasında sıklıkla askıya alındığı ve devam ettirildiği modern konsollarda, kısa sürede oynanan oyunlarda bile 9 saat çalışma süresinin aşılması, oyunun gözünden “tek bir seans” için beklenmeyen bir durum değil.

Unity'nin deltaTime, bir başka cevapta Peter'ın deneyleriyle ortaya çıkan yüksek hassasiyetli bir zaman kaynağından hesaplandığını varsayarsak , deltaTimekare ölçekli zamanlamalara dayanmak göreceli olarak güvenlidir (sadece çok uzun süreler biriktirmek için deltaTimedeğerleri toplayarak dikkatli olun - küçük artışlar ekleyin. daha büyük bir şamandıra, anlayışlı algoritmalarla telafi etseniz bile , kesin bir kayıp için klasik bir reçetedir ).

Yana fixedDeltaTimeBunun yerine dinamik çerçeveye çerçeve değişmesini değil, set aynı değeri tutar, ayrıca tutarlılık kesin güvenceler almak için FixedUpdate zamanlama duyarlı davranışı koyabilirsiniz. deltaTimebu yöntemlerde uygun sabit deltayı otomatik olarak döndürür. Sabit ve çerçeve güncellemeleri arasında bir vuruş sıklığı olsa da, enterpolasyon ile bunu düzeltebilirsiniz .

Kaçınılması gereken, bir zaman damgasını diğerinden çıkararak hesaplama sürelerini hesaplamaktır . Saatlerce oynadıktan sonra bu feci felaketlere yol açabilir ve bu sayede koşuya erken başladığınızdan çok daha az hassasiyet elde edersiniz. Zaman damgalarını karşılaştırmak sistemleriniz için önemliyse, System.Diagnostics.Stopwatchbunun yerine diğer yöntemleri kullanarak kendi yüksek çözünürlüklü zaman değerinizi oluşturabilirsiniz Time.time.


Unreal da hem tek duyarlıklı kayan nokta olarak oyun süresini ortaya çıkarmak için seçtiği kod ve planları . Gerçek zamanlı olarak zaman damgaları ile çalışabilir ve Unity'de yaptığınız gibi kendi zaman dilimi işlemlerinizi yapabilirsiniz. (Unreal'in zaman damgası türünün 32 bitlik bir döneme dayandığından emin olun ). Unreal olarak C # için uzantılar var.
DMGregory

[Ms] için, 16 484 - 32 768 bandı etrafında hassasiyeti kaybetmeye başlarsınız. Olduğuna göre, sonra kesinlik gevşek olabilir 4h30min sonra, 9h mutlaka bu güven olmaz.
xmedeko

Teknik olarak 4,5-9 saat arasında 0,98 milisaniyede hassasiyete sahipsiniz - hatanın 1,00 milisaniyeyi aştığı noktayı işaretlemeyi seçtim. Ancak mesele iyi ele alınıyor - hassasiyet tüm yol boyunca bozuluyor, bu yüzden daha fazla hassasiyet gerektiren kod daha önce bile yanlış davranmaya başlayabilir.
DMGregory

16

Maksimum şamandıra değeri 3.40282347 * 10 ^ 38, saniye cinsinden ölçülen 10 ^ 31 yıla eşittir (veya milisaniye cinsinden ölçülen 10 ^ 28 yıl). İnan bana, taşmaz.

Ortaya çıkabilecek tek şey yanlışlık. Ancak, tek bir hassas kayan nokta sayısının 7-8 ondalık basamak kesinliği vardır. Saniyeyi ölçmek için kullanıyorsanız, yaklaşık 194 gün boyunca doğrudur. Milisaniye ölçmek sadece 4,5 saat için doğrudur. Bu yüzden tamamen ihtiyacınız olan doğruluğa bağlıdır ve eğer milisaniyede (muhtemelen yapmadığınız) doğru olması gerekiyorsa alternatif yollar bulmanız gerekebilir.


7
Wolfram Alpha , birkaç yıldan bahsetmeye değecek kadar büyük olduğu konusunda tonlayıcı bir fikir sunar: bu, evrenin şu andaki yaşından yaklaşık 20 büyüklüktir. Yirmi kat daha yüksek değil, şu anki yaş artı yirmi daha fazla sıfır.
doppelgreener

1
@ Draco18s Birliğin deltaTime değerini nasıl ölçtüğüne bağlıdır, ancak her kare için bir zaman puanı alırlarsa ve bu ikisini çıkarırlarsa cevabın kesin bir evet olduğunu varsayalım.
LukeG

7
Bu cevap hiç doğru değil. Bir deneme çalıştırabilirsiniz. Döngü içinde birer birer yüzer artış olabilir. 10 000 000'a ulaştıktan sonra artma durur. Bunun nedeni, şamandıralarla uğraşırken küçük sayıları büyük sayılarla doğru şekilde ekleyemezsiniz. Doğru cevap bir @DMGregory tarafından verildi
Seagull

2
@Seagull Hiçbir yerde artış hakkında yazarım. Bir şamandıra ile gösterilen maksimum sayının (yaklaşık) 3,4 * 10 ^ 38 olduğu, bu nedenle (OP tarafından kastedildiği gibi) katı anlamda taşma kurallarının dışında olduğu bir gerçektir. Cevabın neden olduğu gibi yanlış olduğunu anlamıyorum?
LukeG

2
@Seagull LukeG'nin cevabının doğru olduğunu düşünüyorum (düzenlemelerdeki gelişmelerden önce bile) - cevabı ve cevabı sadece farklı ihtiyaç sınıflarına atıfta bulunuyor. Float hassasiyeti ve sınırlayıcı durumlar hakkında düşünmeyi seviyorum, LukeG ise konuyu biraz daha geniş bir şekilde ele alıyor, hassas ihtiyaçlara daha az önem veriyor.
DMGregory

12

Oyununuzun ne kadar hassasiyete ihtiyacı var?

32 bitlik bir yüzgeç 24 bit hassasiyete sahiptir. Başka bir deyişle, t zamanında, hassasiyet ± 2 -23 × t'dir . (Bu tam olarak doğru değil, ancak yakın ve tam ayrıntılar çok ilginç değil.)

  • 1ms hassasiyete ihtiyacınız varsa, o zaman 1ms ÷ 2 -23 = 8400 s = 2h 20m sonra, 32 bitlik bir şamandıra kabul edilemez. Çoğu oyun için 1ms'lik bir hassasiyet gerekli değildir, ancak müzikal uygulamalar için gerekli olduğu düşünülür.

  • Oyununuz 144 Hz monitörde çalışıyorsa ve kareye duyarlı grafikler istiyorsanız, 1 ÷ 144 Hz ÷ 2 -23 = 58000 s = 16h sonra, 32 bitlik bir yüzer artık kabul edilemez. 16h, bir oyun çalıştırmak için uzun bir zamandır, ancak düşünülemez. Bahse girerim, önemli bir yüzdemiz, 16 saat boyunca tek bir oyunda oynamıştık - sadece oyunu bıraktığımızda ve biraz uyuduğumuz için bile. Bu noktada, animasyonlar ve fizik güncellemeleri 144Hz'in altına düşürülecekti.

Birlik Time.deltaTimedaha yüksek hassasiyetli bir saatten hesaplanırsa, o zaman bunu kullanabilir ve hala tam bir hassasiyet elde edebilirsiniz. Bunun doğru olup olmadığını bilmiyorum.

Kenar notu

Windows'taki oyunlar ve diğer programlar genellikle GetTickCount()zamanı bulmak için kullanır. Milisaniye saymak için 32 bit bir tam sayı kullandığından, bilgisayarınızı o kadar uzun süre bırakırsanız yaklaşık her 50 günde bir sarar. 50 günlük markette oynuyorsanız, birçok oyunun garip şekillerde takılacağına, çökebileceğine ya da yaramazlık yapabileceğinden şüpheleniyorum.

Windows gibi, tamsayılar GetTickCount()taşma riski taşıyor, Unity'ler gibi yüzer Time.timekonumlarda hassasiyet kaybı var.


10

Diğer cevaplar sadece spekülasyondur, bu yüzden basit bir Birlik projesi yazdım ve bir süre çalışmasına izin verdim. Birkaç saat sonra bu sonuç:

  • UnityEngine.Time.timedoğruluğunu oldukça hızlı bir şekilde kaybeder. Beklendiği gibi, oyunu 4 saat çalıştırdıktan sonra, değerler 1 milisaniye atlar ve bunun ardından yanlışlık artar.
  • UnityEngine.Time.deltaTimeUnity saatlerce çalıştıktan sonra bile ilk alt milisaniye doğruluğunu koruyor. Dolayısıyla deltaTime, platforma bağlı yüksek çözünürlüklü bir sayaçtan türetilen (genellikle 10-1000 yıl sonra taşan) neredeyse garanti edilir . deltaTimeBazı platformlarda hala hassasiyetini kaybedecek küçük bir risk var .

Zamanın yanlış olması, bağlı olan her şey için bir sorundur UnityEngine.Time.time. Spesifik bir örnek, genellikle dayanan rotasyondur (örn. Yel değirmeni) UnityEngine.Mathf.Sin(UnityEngine.Time.time*rotationSpeed). Daha da fazlası, _Timegölgelendiricilerin canlandırması için açıkça kullanılan bir konudur . Fark edilmeye başlamadan önce yanlışlığın ne kadar yüksek olması gerekir? 20-30 msn doğruluk (2 gün), konunun farkında olan ve dikkat eden kişilerin dikkatini çekeceği nokta olmalıdır. 50-100 msn (5-10 gün) problemi bilmeyen hassas insanlar bunu çözmeye başlayacaktır. 200-300 ms'den (20-30 gün) problem belli olacak.

Şimdiye kadar doğruluğunu test etmedim _SinTime, _CosTimeve Unity_DeltaTimeben bu konuda yorum yapamam bu yüzden.

Bu test için kullandığım Script. Bir UI.Textelemana ekli olarak , projenin Oyuncu Ayarları projenin arka planda iken çalışmasına izin verir ve Kalite Ayarları'ndaki VSync Her Saniye Boşta olarak ayarlanır:

public class Time : UnityEngine.MonoBehaviour {
    void Start () {
        LastTime = (double)UnityEngine.Time.time;
        StartTime =  System.DateTime.Now;
        LastPrintTime =  System.DateTime.Now;
    }
    double LastTime;
    System.DateTime StartTime;
    System.DateTime LastPrintTime;
    void Update () {
        double deltaTimeError = (double)UnityEngine.Time.deltaTime - ((double)UnityEngine.Time.time - LastTime);
        if (System.DateTime.Now - LastPrintTime  > System.TimeSpan.FromMilliseconds(1000))
        {
            GetComponent<UnityEngine.UI.Text>().text = "StartTime: " + StartTime.ToLongTimeString()
                + "\nCurrentTime: " + System.DateTime.Now.ToLongTimeString()
                + "\n\nTime.deltaTime: " + UnityEngine.Time.deltaTime.ToString("0.000000")
                + "\nTime.time - LastTime: " + ((float)(UnityEngine.Time.time - LastTime)).ToString("0.000000")
                + "\nAbsolute Error: " +  System.Math.Abs(deltaTimeError).ToString("0.000E0");
            LastPrintTime = System.DateTime.Now;
        }
        LastTime = UnityEngine.Time.time;       
    }
}

görüntü tanımını buraya giringörüntü tanımını buraya giringörüntü tanımını buraya girin görüntü tanımını buraya girin

0.033203Değeri merak ediyorsanız 0.033203125, bunun ikili bir kayan nokta gösterimi olan aslında olduğuna eminim 00111101000010000000000000000000. 0Mantisisteki birçok s dikkat edin .

Geçici Çözümler

Çoğu tür bir geçici çözüme ihtiyaç duymaz. Çoğu oyuncu toplam 100 saat boyunca bir oyun bile oynamaz, bu yüzden bir sorunu çözmek için para yatırmak, insanların sadece birkaç gün süren sürekli oyun süresinin ekonomik olarak uygun olmadığını fark edeceğini fark eder. Ne yazık ki, bazı önemli dezavantajları beraberinde getirmeden sorunun tamamını düzelten basit bir evrensel çözüm bulamıyorum.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.