- Home /
Time.deltaTime not measuring seconds accurately
So, when i use this code it is supposed to be resetting the timer and 1 every time, then it subtracts until it gets to less than or equal to 0, then it gets set back to 1, and the process repeats in order to have a consistent timer to know when to do this method. However, when I press play, it enters the debug message way more than once a second, to the point that it is obvious to the naked eye. Why is it acting like this? (timescale put in for assurance.) using System.Collections; using System.Collections.Generic; using UnityEngine;
public class Hearth_AOE : MonoBehaviour { float ticktimer; // Start is called before the first frame update void Start() { Time.timeScale = (float)1.0; ticktimer = 1; }
// Update is called once per frame
void Update()
{
}
void OnTriggerStay(Collider other)
{
if (other.gameObject.tag == "Ally" && ticktimer <= 0)
{
other.gameObject.GetComponent<Ally>().DoHealing(5);
ticktimer = 1;
if (gameObject.transform.position.y > 0)
{
Debug.Log(ticktimer);
}
if (other.gameObject.GetComponent<Ally>().health > 200)
{
other.gameObject.GetComponent<Ally>().health = 200;
}
}
ticktimer = ticktimer - Time.deltaTime;
}
}
Time.deltaTime is really for use in Update. OnTriggerStay is called during physics steps, which are at a different rate than frames. And Time.deltaTime magically changes into Time.fixedDeltaTime if you use it in certain places.
A safer way is to preset the time and wait for it. Just let the time increase on its own: tickTimer=Time.time+1.0; // 1 second from now ... if(Time.time>=tickTimer)
Answer by NorthStar79 · Nov 14, 2019 at 05:27 AM
OnTriggerStay is called right after all Physics Updates are done. Using DeltaTime causes this kind of problem if used in "OnTrigger" and "OnCollision" methods. You should use FixedDeltaTime instead.
Edit If this answer does not solve your problem, please check the comments below, As Bunny83 points that You may have more than one triggers overlapping.
You are correct. DeltaTime does not measure seconds accurately...
use: FixedDeltaTime
Before this gets any more action, Time.deltaTime
and Time.fixedDeltaTime
give the same value when called during the physics cycle:
void OnTriggerStay(Collider col)
{
Debug.Log($"{Time.deltaTime} vs. {Time.fixedDeltaTime}");
}
But that means the OP's code should be working perfectly: OnTriggerStay gets called exactly 50 times (during physics steps) and Time.deltaTime is auto-converted to the correct value of 1/50th.
Something else must be wrong. The old OnTriggerStay could skip frames, but that would make it count down slower, not faster.
Since the OP doesn't check the actual trigger / collider he's colliding with, it's possible that more than one collider is overlapping that trigger and OnTriggerStay is called once for every collider. He just checks the tag of the collider. However only for the code inside the if statement. The ticktimer increase happens unconditionally for every collider.
You are correct, Unity "Usually" converts deltaTime to fixedDeltaTime automatically if it is used in Physics Cycle. But not always. Don't know why and when exactly. Probably a bug. Exact same thing happened to me too once, I didn't dig very deep into it. If someone able to reproduce this bug reliably we should report it.
Answer by Lightning_A · Nov 14, 2019 at 12:52 AM
I'm sorry, I couldn't actually find out why your timer was calling more than once a second. Double check that it's actually going more than once a second, maybe send a screenshot? Anyways, I made a couple general improvements to your code. I'm sure it could still be better, but I made it so you can change the duration to whatever you want and I also did a couple small things that should increase the performance a little.
public class Hearth_AOE : MonoBehaviour {
public float tickTimerDuration;
float ticktimer;
GameObject ally;
Ally allyScript;
void Start() {
//you shouldn't need to declare the time scale here, you've already proven that that's not the issue
ticktimer = tickTimerDuration;
}
// Update is called once per frame
void Update()
{
}
void OnTriggerEnter(Collider other)
{
if(other.gameObject.CompareTag("Ally")
{
//you could also make ally public and assign it in the inspector if that works for your game
//doing this caches "ally" which is much more performant and convienient than constantly calling GetComponent;
ally = other.gameObject;
allyScript = ally.GetComponent<Ally>();
ticktimer = tickTimerDuration;
}
}
void OnTriggerStay(Collider other)
{
if (other.gameObject.CompareTag("Ally") && ticktimer <= 0)
{
ticktimer = tickTimerDuration;
allyScript.DoHealing(5);
if (gameObject.transform.position.y > 0)
{
Debug.Log(ticktimer);
}
if (allyScript.health > 200)
{
allyScript.health = 200;
}
}
ticktimer -= Time.deltaTime;
}
Thank you for the suggestion, i shall put all the changes i can find in your code into $$anonymous$$e.
Answer by jbaujb · Nov 14, 2019 at 06:19 AM
I do my timers like this:
float timer; float timeToWaitInSeconds; void Update() { if (timer % 60 >= timeToWaitInSeconds) { //do whatever timer = 0; } }
Your answer
Follow this Question
Related Questions
Countdown timer using Time.unscaledDeltaTime not working as expected. 1 Answer
Changing Time.fixedDeltaTime to create slowmotion messes up with physics. 1 Answer
how to reset deltatime back to 1f when scene has reloaded?, 1 Answer
Pause & Unpause Different timers 1 Answer
2nd independent deltaTime and timeScale variables, or a way to mimic this? 1 Answer