我正在使用浮点计算并显示玩家离开(以秒为单位)完成游戏的时间。
在我的游戏时间有时会变得更快,所以留下的时间值需要大。
这是我的问题:我在更新中使用以下代码:
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,但这不起作用:计时器停留在较大的值。
答案 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");
}