Điều gì xảy ra khi Time.time trở nên rất lớn trong Unity?


37

Như đã nói ở đây :

Thời gian

Thời gian ở đầu khung này (Chỉ đọc). Đây là thời gian tính bằng giây kể từ khi bắt đầu trò chơi.

Và như tôi biết thời gian được lưu trữ trong float. Vì vậy, câu hỏi của tôi là điều gì sẽ xảy ra khi giá trị của thời gian trở nên rất lớn? Nó có thể tràn? Nó sẽ mất độ chính xác và gây ra lỗi? Trò chơi sẽ sụp đổ hay sao?


6
Chỉ để biết bối cảnh, hãy xem Kỷ lục Guinness về cuộc đua marathon dài nhất .
Theraot

5
@AlexandreVaillancourt Tôi nghĩ rằng có một câu hỏi hữu ích ở đây nếu chúng ta giải thích nó là "Có vấn đề gì khi Time.time trở nên rất lớn không?" trái ngược với việc tập trung theo nghĩa đen vào "tràn" một mình. Tôi đã chỉnh sửa câu hỏi dọc theo những dòng này để cố gắng giải quyết phản hồi của bạn.
DMGregory

2
@DMGregory Nhưng câu hỏi đã được trả lời và được chấp nhận ... Tôi đồng ý các chỉnh sửa của bạn tạo ra một câu hỏi hữu ích hơn, chỉ hơi muộn.
MichaelHouse

Tôi đã cố gắng diễn đạt các chỉnh sửa để câu trả lời được chấp nhận vẫn là một câu trả lời đúng cho phiên bản đã chỉnh sửa. (Rốt cuộc, nó đã nói về các vấn đề chính xác) Tôi sẽ không vi phạm nếu nó quay trở lại.
DMGregory

Câu trả lời:


62

Có nguy cơ thực sự làm mất độ chính xác về thời gian khi sử dụng phao chính xác đơn .

Nó vẫn sẽ giữ độ chính xác đến giây gần nhất trong 97 ngày . Nhưng trong các trò chơi, chúng tôi thường quan tâm đến độ chính xác theo thứ tự thời lượng khung hình.

Giá trị thời gian nổi chính xác đơn tính bằng giây bắt đầu mất độ chính xác mili giây sau khoảng 9 giờ .

Điều đó đã không nằm ngoài khả năng cho một phiên chơi duy nhất hoặc để trò chơi chạy "AFK" khi bạn đang ở cơ quan / trường học hoặc đang ngủ. (Đây là một lý do tại sao một cách phổ biến để kiểm tra trò chơi là chạy nó qua đêm và kiểm tra xem nó có còn chơi đúng vào buổi sáng không)

Trên các bảng điều khiển hiện đại, nơi các trò chơi thường bị đình chỉ và tiếp tục giữa các phiên chơi thay vì tắt hoàn toàn, không có gì bất ngờ khi một "phiên duy nhất" từ chế độ xem mắt của trò chơi vượt quá 9 giờ thời gian chạy ngay cả khi chơi trong các đợt ngắn.

Giả sử Unity deltaTimeđược tính từ nguồn thời gian có độ chính xác cao hơn, được đưa ra bởi các thí nghiệm của Peter trong một câu trả lời khác, dựa vào deltaTimethời gian quy mô khung là tương đối an toàn (chỉ cần thận trọng khi tích lũy thời lượng rất dài bằng cách cộng deltaTimecác giá trị nhỏ một float lớn hơn là một công thức cổ điển cho sự mất chính xác, ngay cả khi bạn bù bằng các thuật toán hiểu biết ).

fixedDeltaTimegiữ nguyên giá trị bạn đã đặt, thay vì tự động thay đổi từ khung này sang khung khác, bạn cũng có thể đặt hành vi nhạy cảm với thời gian trong FixedUpdate để có được sự đảm bảo mạnh mẽ hơn về tính nhất quán. deltaTimesẽ tự động trả về delta cố định thích hợp trong các phương thức này. Mặc dù có thể có tần số nhịp giữa các bản cập nhật cố định & khung, bạn có thể làm mịn điều này thông qua phép nội suy .

Những gì bạn muốn tránh là tính toán thời lượng bằng cách trừ một dấu thời gian từ một dấu thời gian khác . Sau nhiều giờ chơi, điều này có thể gây ra sự hủy bỏ thảm khốc, dẫn đến độ chính xác thấp hơn nhiều so với bạn có được ngay từ đầu. Nếu so sánh dấu thời gian là quan trọng đối với hệ thống của bạn, bạn có thể tạo giá trị thời gian có độ phân giải cao hơn của riêng mình bằng các phương pháp khác, như System.Diagnostics.Stopwatchthay vì Time.time.


Unreal cũng chọn hiển thị thời gian trò chơi dưới dạng nổi chính xác duy nhất, trong cả bản thiết kế . Bạn có thể làm việc xung quanh nó với dấu thời gian trong thời gian thực và thực hiện việc giãn thời gian của riêng bạn, giống như bạn làm trong Unity. (Chỉ cần xem loại dấu thời gian của Unreal dựa trên epoch 32 bit ). Tiện ích mở rộng tồn tại cho C # trong Unreal nếu bạn chọn.
DMGregory

Đối với [ms], bạn bắt đầu mất độ chính xác trong khoảng 16 484 - 32 768 băng tần. Tức là bạn có thể mất độ chính xác sau 4h30 phút , sau 9h bạn chắc chắn không thể tin vào điều đó.
xmedeko

Về mặt kỹ thuật trong khoảng 4,5-9 giờ, bạn có độ chính xác trong vòng 0,98 mili giây - Tôi đã chọn gắn cờ điểm mà lỗi vượt quá 1,00 mili giây. Nhưng vấn đề được thực hiện tốt - độ chính xác suy giảm trong suốt quá trình, do đó, mã cần độ chính xác cao hơn có thể bắt đầu hoạt động sai thậm chí sớm hơn.
DMGregory

16

Giá trị nổi tối đa là 3,40282347 * 10 ^ 38, tương đương 10 ^ 31 năm khi tính bằng giây (hoặc 10 ^ 28 năm khi tính bằng mili giây). Tin tôi đi, nó sẽ không tràn ra đâu.

Điều duy nhất có thể xuất hiện là không chính xác. Nhưng một số dấu phẩy động chính xác duy nhất có độ chính xác 7-8 chữ số thập phân. Nếu sử dụng nó để đo giây, nó chính xác trong khoảng 194 ngày. Nếu đo mili giây thì chính xác chỉ trong 4,5 giờ. Vì vậy, nó hoàn toàn phụ thuộc vào độ chính xác bạn cần và bạn có thể cần tìm các cách khác nếu bạn cần chính xác đến mili giây (mà bạn có thể không biết).


7
Wolfram Alpha cung cấp một ý tưởng thiết lập giai điệu về số năm có thể đáng nói đến: nó cao hơn khoảng 20 độ so với tuổi hiện tại của vũ trụ. Không phải cao hơn hai mươi lần , nhưng tuổi hiện tại cộng thêm hai mươi số không.
doppelgreener

1
@ Draco18s Phụ thuộc vào cách thống nhất đo lường deltaTime, nhưng nếu họ lấy điểm thời gian cho mỗi khung và trừ hai khung đó, tôi cho rằng câu trả lời là có.
LukeG

7
Câu trả lời này không đúng chút nào. Bạn có thể chạy thử nghiệm. Bạn có thể tăng từng cái một trong vòng lặp. Sau khi đạt 10 000 000, nó sẽ ngừng tăng. Lý do là bạn không thể thêm số nhỏ vào số lớn một cách chính xác khi bạn đang xử lý float. Câu trả lời đúng được đưa ra bởi một @DMGregory
Seagull

2
@Seagull Không ở đâu tôi viết về tăng dần. Có một thực tế là số lượng tối đa có thể biểu thị bằng một số float là (khoảng) 3,4 * 10 ^ 38, do đó, các quy tắc sẽ tràn ra theo nghĩa chặt chẽ (theo nghĩa của OP). Tôi không thấy lý do tại sao câu trả lời sẽ không chính xác?
LukeG

2
@Seagull Tôi nghĩ rằng câu trả lời của LukeG là chính xác (ngay cả trước những cải tiến trong các chỉnh sửa) - câu trả lời của anh ấy và của tôi chỉ đề cập đến các loại nhu cầu khác nhau. Tôi thích tìm hiểu về độ chính xác của phao và các trường hợp giới hạn, trong khi LukeG xem xét vấn đề rộng hơn một chút, ít chú trọng đến việc xác định chính xác nhu cầu chính xác.
DMGregory

12

Trò chơi của bạn cần bao nhiêu độ chính xác?

Một float 32 bit có độ chính xác 24 bit. Nói cách khác, tại thời điểm t, độ chính xác là ± 2 -23 × t. (Điều này không chính xác, nhưng nó rất gần và các chi tiết chính xác không thú vị lắm.)

  • Nếu bạn cần độ chính xác 1ms, thì sau 1ms 2 -23 = 8400 s = 2h 20m, độ nổi 32 bit không còn được chấp nhận. Độ chính xác 1ms là không cần thiết cho hầu hết các trò chơi, nhưng nó được coi là cần thiết cho các ứng dụng âm nhạc.

  • Nếu trò chơi của bạn chạy trên màn hình 144 Hz và bạn muốn đồ họa chính xác theo khung, thì sau 1 ÷ 144 Hz 2 -23 = 58000 s = 16h, độ nổi 32 bit không còn được chấp nhận. 16h là một thời gian dài để chạy một trò chơi, nhưng nó không thể tưởng tượng được. Tôi cá là một tỷ lệ đáng kể trong số chúng tôi đã chạy một trò chơi trong 16 giờ trong một lần duy nhất - ngay cả khi chúng tôi rời khỏi trò chơi và ngủ một chút. Tại thời điểm đó, hình ảnh động và cập nhật vật lý sẽ giảm xuống dưới 144Hz.

Nếu Unity Time.deltaTimeđược tính từ đồng hồ có độ chính xác cao hơn, thì bạn có thể sử dụng nó và vẫn có được độ chính xác đầy đủ. Tôi không biết điều này có đúng hay không.

Lưu ý bên

Các trò chơi và các chương trình khác trên Windows thường sử dụng GetTickCount()để tìm ra thời gian. Vì nó sử dụng số nguyên 32 bit để đếm mili giây, nên nó sẽ kết thúc khoảng 50 ngày một lần, nếu bạn rời khỏi máy tính của mình trên đó. Tôi nghi ngờ rằng nhiều trò chơi sẽ bị treo, bị sập hoặc hoạt động sai theo những cách kỳ quái nếu bạn chơi chúng ở mốc 50 ngày.

Các số nguyên, như Windows ' GetTickCount(), có nguy cơ tràn, trong khi các số float, như Unity Time.time, có nguy cơ mất độ chính xác.


10

Các câu trả lời khác chỉ suy đoán, vì vậy tôi đã viết một dự án Unity đơn giản và để nó chạy một lúc. Sau một vài giờ, đây là kết quả:

  • UnityEngine.Time.timemất độ chính xác khá nhanh. Như mong đợi, sau khi chạy trò chơi trong 4 giờ, các giá trị tăng thêm 1 mili giây và độ chính xác sẽ tăng lên sau đó.
  • UnityEngine.Time.deltaTimegiữ độ chính xác dưới một phần nghìn giây ban đầu ngay cả sau khi Unity đã chạy hàng giờ. Do đó, nó hầu như được đảm bảo có deltaTimenguồn gốc từ bộ đếm độ phân giải cao phụ thuộc vào nền tảng (thường tràn sau 10-1000 năm). Vẫn còn một rủi ro nhỏ deltaTimevẫn sẽ mất độ chính xác trên một số nền tảng.

Sự không chính xác của Thời gian là một vấn đề cho mọi thứ phụ thuộc vào UnityEngine.Time.time. Một ví dụ cụ thể là xoay (ví dụ của cối xay gió), thường dựa trên UnityEngine.Mathf.Sin(UnityEngine.Time.time*rotationSpeed). Thậm chí nhiều vấn đề được _Timesử dụng rõ ràng cho hoạt hình của các shader. Sự thiếu chính xác cần phải cao đến mức nào trước khi nó bắt đầu trở nên đáng chú ý? Độ chính xác 20-30 ms (2 ngày) sẽ là điểm mà những người nhận thức được vấn đề và chú ý kỹ, sẽ chú ý. Ở mức 50-100 ms (5-10 ngày) những người nhạy cảm không biết về vấn đề này sẽ bắt đầu tìm ra vấn đề. Từ 200-300 ms (20-30 ngày), vấn đề sẽ rõ ràng.

Cho đến nay tôi đã không kiểm tra tính chính xác của _SinTime, _CosTimeUnity_DeltaTime, vì vậy tôi không thể bình luận về những.

Đây là Script tôi đã sử dụng để thử nghiệm. Được đính kèm với một UI.Textyếu tố, Cài đặt trình phát của dự án cho phép dự án chạy trong khi ở chế độ nền và VSync trong Cài đặt chất lượng được đặt thành Mỗi giây V trống:

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;       
    }
}

nhập mô tả hình ảnh ở đâynhập mô tả hình ảnh ở đâynhập mô tả hình ảnh ở đây nhập mô tả hình ảnh ở đây

Nếu bạn đang tự hỏi về 0.033203giá trị, tôi khá chắc chắn rằng đó thực sự 0.033203125là một đại diện dấu phẩy động nhị phân 00111101000010000000000000000000. Chú ý nhiều 0s trong lớp phủ.

Cách giải quyết

Hầu hết các thể loại không cần một cách giải quyết. Hầu hết người chơi thậm chí sẽ không chơi một trò chơi trong tổng số 100 giờ, vì vậy, đầu tư tiền để khắc phục sự cố mọi người sẽ chỉ nhận thấy sau một vài ngày giả định về thời gian chơi liên tục là không khả thi về mặt kinh tế. Thật không may, tôi không thể đưa ra một cách giải quyết phổ quát đơn giản giúp khắc phục toàn bộ vấn đề mà không mang theo một số nhược điểm đáng kể.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.