正如这里所说的:
时间
该帧开始的时间(只读)。这是自游戏开始以来的时间(以秒为单位)。
据我所知,时间存储在float中。因此,我的问题是,当时间价值变得非常大时会发生什么?它会溢出吗?它会失去精度并导致错误吗?游戏会崩溃还是会崩溃?
正如这里所说的:
时间
该帧开始的时间(只读)。这是自游戏开始以来的时间(以秒为单位)。
据我所知,时间存储在float中。因此,我的问题是,当时间价值变得非常大时会发生什么?它会溢出吗?它会失去精度并导致错误吗?游戏会崩溃还是会崩溃?
Answers:
它仍然可以将精度保持到最近的97秒。但是在游戏中,我们经常关心帧持续时间的准确性。
约9小时后,以秒为单位的单精度浮点时间值开始失去毫秒精度。
这已经不在单人游戏时段的范围之内,或者在您上班/上学或睡觉时让游戏运行“ AFK”。(这就是为什么测试游戏的一种常见方法是通宵运行游戏并检查其在早上仍能正常播放的原因之一)
在现代游戏机上,游戏通常在游戏时段之间暂停和恢复,而不是完全关闭,因此从游戏的角度来看,“单个时段”超过9小时的运行时间就不足为奇了,即使是短暂播放也是如此。
假设Unity的deltaTime
计算是由高精度时间源计算的,这在Peter的另一个答案中得到了证实,那么依赖deltaTime
帧尺度的定时是相对安全的(请谨慎通过求和来累积很长的时间deltaTime
-将小增量添加到即使使用精明的算法进行补偿,较大的浮点数也是降低精度的经典方法。
由于fixedDeltaTime
保持与您设置的相同值,而不是逐帧动态更改,因此还可以将定时敏感的行为放入FixedUpdate中,以获得更强的一致性保证。deltaTime
将在这些方法中自动返回适当的固定增量。尽管固定和帧更新之间可能有拍子频率,但您可以通过插值来使其平滑。
您要避免的是通过从另一个时间戳中减去一个时间戳来计算持续时间。玩了几个小时后,这可能会导致灾难性的取消,导致精度大大低于您在运行初期获得的精度。如果比较时间戳记对您的系统很重要,则可以使用其他方法(例如System.Diagnostics.Stopwatch
而不是)来生成自己的高分辨率时间值Time.time
。
float的最大值为3.40282347 * 10 ^ 38,以秒为单位等于10 ^ 31年(如果以毫秒为单位,则等于10 ^ 28年)。相信我,它不会溢出。
可能会出现的唯一错误是准确性。但是单个精度浮点数的精度为7-8个十进制数字。如果使用它来测量秒,则它的精确度约为194天。如果以毫秒为单位,则仅在4.5小时内是准确的。因此,它完全取决于所需的精度,如果需要精确到毫秒(可能不需要),则可能需要寻找其他方法。
您的游戏需要多少精度?
32位浮点型具有24位精度。换句话说,在时间t处,精度为±2 -23 ×t。(这并不完全正确,但是很接近,确切的细节并不是很有趣。)
如果需要1ms的精度,则在1ms÷2 -23 = 8400 s = 2h 20m之后,将不再接受32位浮点数。大多数游戏都不需要1ms的精度,但是对于音乐应用来说,它被认为是必需的。
如果您的游戏在144 Hz监视器上运行,并且您需要帧精确的图形,则在1÷144 Hz÷2 -23 = 58000 s = 16h之后,将不再接受32位浮点数。16h是长时间玩游戏,但这并非不可想象。我敢打赌,我们当中有很大一部分人一次连续运行了16个小时的游戏-即使只是因为我们让游戏保持运行并睡了一段时间。到那时,动画和物理更新将减少到144Hz以下。
如果Unity的Time.deltaTime
时钟是从高精度时钟计算出来的,那么您可以使用该时钟,并且仍然可以获得全精度。我不知道这是不是真的。
Windows上的游戏和其他程序经常用来GetTickCount()
计算时间。由于它使用32位整数来计数毫秒,因此,如果您将计算机放置在这么长的时间内,它大约每50天就会回绕一次。我怀疑如果您在50天的时间里玩游戏,许多游戏将以异常的方式挂起,崩溃或行为异常。
像Windows一样的整数GetTickCount()
有溢出的风险,而像Unity一样的浮点数则Time.time
有失去精度的风险。
其他答案仅是推测,因此我编写了一个简单的Unity项目,并使其运行了一段时间。几个小时后,结果如下:
UnityEngine.Time.time
相当快地失去准确性。不出所料,在运行游戏4个小时后,值跳了1毫秒,此后误差确实会增加。UnityEngine.Time.deltaTime
即使Unity运行了几个小时,它仍保持最初的毫秒级精度。因此,实际上可以保证它 deltaTime
源自与平台相关的高分辨率计数器(通常在10-1000年后溢出)。仍然存在微小的风险,deltaTime
在某些平台上仍然会失去精度。时间的不准确性是所有依赖的问题UnityEngine.Time.time
。一个具体的例子是旋转(例如风车),通常基于UnityEngine.Mathf.Sin(UnityEngine.Time.time*rotationSpeed)
。_Time
着色器明确将其用于动画的问题更多。在开始变得不明显之前,不准确度需要达到多少?意识到这一问题并密切注意的人应该注意到20-30毫秒的准确性(2天)。在50-100毫秒(5-10天)内,不知道该问题的敏感人员将开始解决该问题。在200-300毫秒(20-30天)内,问题将很明显。
到目前为止,我还没有测试的准确性_SinTime
,_CosTime
以及Unity_DeltaTime
,所以我不能对这些评论。
这是我用于测试的脚本。它附加到UI.Text
元素上,项目的“播放器设置”允许项目在后台运行,并且“质量设置”中的“垂直同步”设置为“每秒第二个V空白”:
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;
}
}
如果您想知道该0.033203
值,我可以肯定的是0.033203125
,它的二进制浮点表示形式为00111101000010000000000000000000
。注意0
尾数中的许多。
解决方法
大多数类型不需要变通办法。大多数玩家甚至根本不会玩100个小时的游戏,因此,投入金钱来解决问题只会在假设的连续连续几天玩游戏在经济上不可行之后才会引起人们的注意。不幸的是,我无法提出一个简单的通用解决方法来解决整个问题,而又不会带来一些重大缺陷。