在Unity3d中使用大浮点值作为计时器

时间:2017-09-23 08:15:04

标签: c# unity3d

我正在使用浮点计算并显示玩家离开(以秒为单位)完成游戏的时间。

在我的游戏时间有时会变得更快,所以留下的时间值需要大。

这是我的问题:我在更新中使用以下代码:

  Update () {
            timeleft -= Time.deltaTime;
            Debug.Log (timeleft);
            counter.text = "Time Left = " +timeleft.ToString("F0");
    }

在游戏开始时,剩余时间值设置为非常高的数字(3200万,大约一年,以秒为单位)。

时间下降的速度在游戏中有所不同,所以我使用的是带有time.deltaTime的浮点数。

Unity将这个大的初始值存储为3.2E + 07。 一旦发生这种情况,我的counter.text就不再正常工作,因为它只是等到下一个科学记数值出现。因此看起来计时器文本被卡住了,而在后面它实际上仍在倒计时。希望我在这里有意义。为避免疑问:计数器显示适用于低于100万的值。

如何解决此问题?如何转换timeleft.ToString以使其显示正确的值?

根据以下评论,有人建议使用小数代替。那不能使用deltaTime,因为它需要一个浮点数,或者我误解了在哪里以及如何使用小数。

我尝试创建一个新的int并在float上使用Mathf.RoundToInt,但这不起作用:计时器停留在较大的值。

1 个答案:

答案 0 :(得分:1)

这里的简短道德是浮点运算不符合普通人类对数字的直觉。

你写道:

  

Unity将这个大的初始值存储为3.2E + 07。一旦那个   碰巧,我的counter.text不再正常工作了   等到下一个科学记数值出现。所以它看起来   就像计时器文本被卡住一样,而在后面它实际上仍然是   倒计时。

这是不正确的:不仅文本没有改变,数字本身不会因Time.deltaTime的小值而改变。问题是随着值变大,float的精度会降低。此外,由于底层存储格式为binary floating-point,因此下一个最大和次最小数字之间的“差距”很难直观。

您可以使用以下代码自行测试:

float f = 3.2e7f;
string s1 = f.ToString();
Console.WriteLine(s1);
string s2 = f.ToString("F0");
Console.WriteLine(s2);
string s3 = (f - 7).ToString("F0");

var f2 = f;
for (int i = 0; i < 3000000; i++)
{
    f2 = f2 - 1f;
}
var diff = f - f2;
Debug.Log(diff);
if (f2 == f) 
{
    Debug.Log("Floating point numbers are strange.");
}

f2的值永远不会改变,尽管据说减少了300万次。这是因为3.2e7f - 1f 完全等于 3.2e7f

正如评论中所指出的,解决方案是使用decimal,它使用基数为10的格式,并且更符合人类的直觉。这将正确倒计时。

  decimal timeLeft = 3.2e7M;
  Update () {
            timeleft -= (decimal)Time.deltaTime;
            Debug.Log (timeleft);
            counter.text = "Time Left = " +timeleft.ToString("F0");
}