简体   繁体   中英

Using a large float value as a timer in Unity3d

I am using a float to calculate and display the time the player has left (in seconds) to finish the game.

In my game time sometimes goes faster, so the time left value needs to go big.

Here's my problem: I use the following code in Update:

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

At game start, the time left value is set to a really high number (32 million, about a year in seconds).

The rate at which the time drops varies in the game, so I am using a float with time.deltaTime.

Unity stores this big initial value as 3.2E+07. As soon as that happens, my counter.text doesn't work properly anymore, as that just waits until the next scientific notation value comes up. So it looks like the timer text is stuck, while in the back it is in fact still counting down. Hope I'm making sense here. For the avoidance of doubt: the counter display works fine for values below 1 million.

How do I fix this problem? How do I convert timeleft.ToString so that it displays the correct value?

As per the comments below, someone suggested to use a decimal instead. That won't work with deltaTime as that needs a float or I misunderstood where and how to use the decimal.

I tried to create a new int and use Mathf.RoundToInt on the float, but that doesnt work: the timer stays stuck at the larger value.

The short moral here is that floating-point arithmetic doesn't conform to ordinary human intuitions about numbers.

You write:

Unity stores this big initial value as 3.2E+07. As soon as that happens, my counter.text doesn't work properly anymore, as that just waits until the next scientific notation value comes up. So it looks like the timer text is stuck, while in the back it is in fact still counting down.

This is incorrect: it's not just the text that's not changing, the number itself isn't changing for small values of Time.deltaTime . The problem is that the precision of float reduces as the value gets larger. Moreover, since the underlying storage format is binary floating-point , the 'gap' between the next-largest and next-smallest number is difficult to intuit.

You can test this yourself with the following code:

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.");
}

The value of f2 never changes, despite being supposedly decremented 3 million times. This is because 3.2e7f - 1f is exactly equal to 3.2e7f .

The solution, as pointed out in the comments, is to use decimal , which uses a base-10 format and conforms much better to human intuitions. This will count down correctly.

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM