- Home /
Time.DeltaTime not correctly incrimenting timer?
So... I may just be stupid, but the simplest part of my little game here seems to be malfunctioning and I do not know why.
In short... In my GameController script (tracks everything) I have
void Start(){ float timer = 0.0f; }
void Update(){ timer += Time.deltaTime; }
Now the game displays the time it took in seconds at the end by simply setting the value of a text field to "timer.ToString();", but it's always way more than the actual time since the scene was loaded.
If my stopwatch times it at, say, 12 seconds - the timer reads over 20. I used my stopwatch to wait exactly 30 seconds, the timer read 120 seconds. I tried to find some kind of consistency to indicate the issue but there doesn't seem to be any... seems to just be fairly randomly "adding" time as it goes along. I've looked into the phenomenon of time drift but I doubt that's my problem.
EDIT: Alrighty, I'll post the full code (At least everything that contains this variable. It's gonna be long lol...
public GameObject scrollingBackground;
private GameObject tile1, tile2;
private float moveSpeed, tileHeight, horizontalMoveSpeed, distanceTraveled;
public GameObject joystick;
public float maxShipSpeed, horizontalMovementMultiplier = 1.0f;
public GameObject ship;
public GameObject laserPrefab;
public Text speedText, distanceText, scoreText;
private float score;
private float shipHealth, shieldHealth;
public Image healthBar, shieldBar;
public float asteroidDamage;
public float shieldRechargeTimer, shieldRechargeRatePerSecond;
private float timerForShields;
private bool shieldIsRecharging = false;
public GameObject shipDeathExplosion;
private bool shipAlive = true;
public GameObject dataTracker;
--> private float gameTime;
private static DataManagerScript dataManager;
// Use this for initialization
void Start () {
dataManager = DataManagerScript.dataManager;
distanceTraveled = 0;
tile1 = scrollingBackground.transform.GetChild(0).gameObject;
tile2 = scrollingBackground.transform.GetChild(1).gameObject;
tileHeight = tile1.GetComponent<Renderer>().bounds.size.y;
moveSpeed = 0.0f;
score = 0;
shipHealth = 100;
shieldHealth = 100;
asteroidDamage = (asteroidDamage == 0) ? 10.0f : asteroidDamage;
shieldRechargeTimer = (shieldRechargeTimer == 0) ? 5.0f : shieldRechargeTimer;
shieldRechargeRatePerSecond = (shieldRechargeRatePerSecond == 0) ? 5.0f : shieldRechargeRatePerSecond;
--> gameTime = 0;
}
// Update is called once per frame
void Update () {
//Timer
--> gameTime += Time.deltaTime;
//HEALTH AND SHIELDS
//SHIELD RECHARGE
timerForShields += Time.deltaTime;
if (timerForShields > shieldRechargeTimer)
{
timerForShields = 0;
shieldIsRecharging = true;
}
if (shieldHealth < 100)
{
shieldHealth += (shieldIsRecharging) ? shieldRechargeRatePerSecond * Time.deltaTime : 0f;
}
shieldHealth = (shieldHealth > 100.0f) ? 100 : shieldHealth;
//SHIELD AND HEALTH BARS
shieldHealth = (shieldHealth < 0) ? 0.0f : shieldHealth;
shipHealth = (shipHealth < 0) ? 0 : shipHealth;
if (shipAlive)
{
if (shipHealth <= 0)
{
Destroy(ship.GetComponent<MeshRenderer>());
Instantiate(shipDeathExplosion, ship.transform.position, new Quaternion(0, 0, 0, 0));
shipAlive = false;
endGameOnDeath();
}
}
shieldBar.rectTransform.localScale = new Vector3(shieldHealth / 100f, 1, 1);
healthBar.rectTransform.localScale = new Vector3(shipHealth / 100f, 1, 1);
//END HEALTH AND SHIELDS
//If Joystick Is Down, Increase Movement Speed
if (joystick.GetComponent<JoystickScript>().isJoystickDown())
{
moveSpeed += joystick.GetComponent<JoystickScript>().Vertical() * Time.deltaTime;
}
//NO GOING BACKWARDS!
if(moveSpeed < 0)
{
moveSpeed = 0;
}
// LIMIT MAX SPEED
moveSpeed = (moveSpeed > maxShipSpeed) ? maxShipSpeed : moveSpeed;
// End Increase Movement Speed
//Horizontal Movement
if (joystick.GetComponent<JoystickScript>().isJoystickDown())
{
horizontalMoveSpeed = joystick.GetComponent<JoystickScript>().Horizontal();
if (horizontalMoveSpeed > 0)
{
if (ship.transform.position.x < 7.5)
{
ship.transform.Translate(Vector3.right * horizontalMoveSpeed * horizontalMovementMultiplier * Time.deltaTime);
}
}else if(horizontalMoveSpeed < 0)
{
if (ship.transform.position.x > -7.5)
{
ship.transform.Translate(Vector3.left * horizontalMoveSpeed * horizontalMovementMultiplier * Time.deltaTime * -1);
}
}
}
//SCROLLING BACKGROUND
tile1.transform.Translate(Vector2.down * Time.deltaTime * moveSpeed);
tile2.transform.Translate(Vector2.down * Time.deltaTime * moveSpeed);
if(tile1.transform.localPosition.y <= -15)
{
tile1.transform.localPosition = new Vector3(Random.Range(-10.0f, 10.0f) , tile1.transform.localPosition.y + tileHeight, tile1.transform.localPosition.z);
}
if (tile2.transform.localPosition.y <= -15)
{
tile2.transform.localPosition = new Vector3(Random.Range(-10.0f, 10.0f), tile2.transform.localPosition.y + tileHeight, tile2.transform.localPosition.z);
}
//END SCROLLING BACKGROUND
distanceTraveled += moveSpeed * Time.deltaTime;
//UI STUFF
speedText.text = "Speed: " + moveSpeed.ToString("N2");
distanceText.text = "Distance: " + Mathf.Round(distanceTraveled);
scoreText.text = score.ToString();
}
Here is "endGameOnDeath()" that is called when the ship's health is <= 0. PreviousGamesLibrary is just a serializable class that holds the score, distance and time of each game which is subsequently stored in a list of PreviousGamesLibrary's to be saved/loaded.
private void endGameOnDeath()
{
dataManager.saveNewGame(new PreviousGamesLibrary(score, distanceTraveled, gameTime));
Invoke("backToMenu", 1);
}
As you can see I use quite a bit of Time.DeltaTime, including for a delay in my ship shield's recharging - which I also timed and also works flawlessly.
The only static anything in this entire project is dataManager which is a single-tin structure class for managing persistent data (I'm not going to pretend I know exactly what that means, I followed a tutorial lol) but that's the only thing I have declared static in the entire project.
Any chance your Time.timeScale is set to a value besides 1? That would account for this. You can use Time.unscaledDeltaTime to grab an increment which does not care about timeScale.
I don't suppose you're manually calling Update from another function or script? Or have multiple instances of this script, where the timer variable is static?
(I'm guessing you mis-spoke when indicating that you declared the timer variable in the Start method. If you did that, you would not have access to it in the Update method.)
I just did that to simplify my explanation, the timer float is declared properly and just instantiated in start. I've never used Time.TimeScale, so it should be at it's default value. I have several other things (movement of objects, scrolling background, etc) that all also use Time.deltaTime in their calculations, so is it possible using Time.deltaTime more than once in the update could be causing an issue? And no, there's only one instance of this script.
Odd-ball thing here but in the same update function I spawn entities every 1 second by doing "float spawnTimer += Time.DeltaTime" "if(spawnTimer >=1){ Instantiate(Spawn), spawntimer =0} and THAT spawns a new entity exactly every 1 second according to my stopwatch, but the timer is still wonky.
Are you absolutely certain that the timer variable is not being written to by any other piece of code? That (or a non-one timescale) is the only possible way I can imagine getting an incorrect value under normal circumstances.
Is the project beco$$anonymous$$g non-responsive during play mode? If your frames-per-second are extremely low, that might cause this kind of issue. Are you sure you've made no changes to the project's timestep or timescale? Perhaps you've disabled vsync?
I'd suggest posting the full code. Just looking at your hints this should work just fine, but probably there is a problem that we cannot see here.
Probably the variable timer
is declared static and there somehow is more than one instance of GameController.
Answer by AurimasBlazulionis · Dec 28, 2016 at 12:37 PM
It is quite strange. This might be a really weird bug with unity (highly unlikely), it might be some problems with getting time from your PC. You can also have the variable altered from other components. Maybe the timer is static!?
I see one problem is that the timer is declared in start (float timer = 0).
You can try moving to FixedUpdate and use Time.fixedDeltaTime instead.
To not have any problems. Just do something like startTime = Time.time
in Start function, and when you update the UI get the time as Time.time - startTime
Answer by ElijahShadbolt · Dec 28, 2016 at 07:27 AM
I wouldn't use Time.deltaTime to measure time any longer than, like, 1 second, because floats do not have enough digits/figures to be accurately added over hundreds of frames. You're bound to be losing or gaining something due to rounding.
Edit: I thought wrong. Ignore that paragraph. Edit 2: If you are running a server with high update frequency (not limited to 60 fps), then perhaps that paragraph may help, so I have kept it in this answer.
I would use Time.time or Time.unscaledTime instead. Or even Time.realtimeSinceStartup. For example,
float timeAtStart;
float timer;
void Start() {
timeAtStart = Time.time;
timer = 0;
}
void Update() {
timer = Time.time - timeAtStart;
}
// at end of game
(Time.time - timeAtStart).ToString();
// or just
timer.ToString();
Note that this is untested.
"floats do not have enough digits/figures to be accurately added over hundreds of frames"
I'm afraid this isn't accurate. If you're talking about hundreds of millions of frames, perhaps. Or in industrial / scientific settings. In the context of video game time management, using a float to accrue deltaTime is 100% fine. Unless you're going to run the application continuously for several consecutive weeks. I'm very confident that this phenomenon is not related the OP's problem.
Answer by Marc477 · Feb 21 at 04:39 AM
Just want to say that I also had this problem, and the issue WAS what ElijahShadbolt mentioned. You should unstroke that paragraph lol, because that is what actually helped me resolve this.
The thing is that I had this issue on a Unity Server build (linux), so since there are no graphics, the frame rate was something crazy like 50000, which did make the Time.deltaTime extremely small for a float. And as a result, the time was moving much slower than supposed.
I solved this issue with :
Application.targetFrameRate = 60;
In the Start function of my main manager.
Your answer

Follow this Question
Related Questions
Delay Player From Using Action Button For A Period Of Time 0 Answers
Why does resetTimer act counter-intuitively? 2 Answers
Android and Time.DeltaTime 0 Answers
Digital Clock Needed For New UI Text 1 Answer
How do I fix this cooldown? 1 Answer