Hi everyone, I’m new to Unity and scripting in general. I am trying to implement a simple enemy spawn timer for my game which is a simple 2d shooter. Unfortunately, “if (timer == value)” does not seem to work. If instead I change “==” with something else, for example “>=” it works perfectly but it’s not what I want.
You should basically never test whether two floats are equal. Floats usually have a lot of digits after the decimal point, and those digits might not be what you are expecting because of roundoff error. (You know how some simple fractions like 1/3 result in an infinite decimal like 0.3333333…? That happens even more in binary; for instance, 0.1 becomes an infinite decimal if you try to write it in binary.)
You can use Mathf.Approximately() to test if two floats are roughly equal. But for timers, you probably shouldn’t even use that, because time advances in discrete chunks of unpredictable size based on how long it takes to render a single frame. Your timer might jump straight from 0.123 seconds to 0.139 seconds without ever taking on any of the values between those.
So, basically: you are correct, == will not work in cases like this. Use stuff like >= instead.
You can use >= in combination with a boolean flag to trigger something only once when a timer passes a particular value:
private bool didPass = false;
void Update() {
if (timer >= value && !didPass) {
didPass = true;
//Do stuff
}
Thank you so much both! I was about to ask Antistone if it would make sense to recall a function only once. It makes sense and seems to work, thanks StarManta for writing the example code so that even a novice like me can understand.
EDIT: There is one last thing I would like to ask. Changing the flag to “true”, when I want to create another function that activates later in time I have to make the flag go back to false, but doing so will also call up the previous function, which I would like to avoid. I could create a second boolean flag but the code would stretch out of proportion, is it correct?
Doing it like that would require 1 boolean per action you are tracking. Having a few booleans in a script for this purpose is not usually something to worry about, though I have learned the hard way to clearly name each so as to not later confuse them.
If you end up needing large numbers of them, then you may want to come up with a different strategy though.
like Joe said if a couple of bools don’t worry about it, if you start getting dozens in a single script you might be doing things in a wrong way…
you could look into a custom class to hold all information relevant to a certain action, keep an array of that and work on that (this won’t change the actual number of variables used, just declaring them a little more “discreetly” (do note you can just collapse a region in the text editor to hide its ugly face)
oh boy that’s a fun day, been there, haha.
If all of your events happen in a single consistent order, you could replace all of the booleans with a single integer that says which step you’re on. e.g.
float elapsedTime = 0;
int step = 0;
void Update()
{
elapsedTime += Time.deltaTime;
if (step == 0 && elapsedTime >= first_time_threshold)
{
++step;
DoFirstThing();
}
if (step == 1 && elapsedTime >= second_time_threshold)
{
++step;
DoSecondThing();
}
if (step == 2 && elapsedTime >= third_time_threshold)
{
++step;
DoThirdThing();
}
// etc.
}
You can maybe even refactor that down to something very small using lists and delegates:
float elapsedTime = 0;
int step = 0;
List<float> timeThresholds;
List<Action> thingsToDo;
void Update()
{
elapsedTime += time.deltaTime;
while (step < timeThresholds.Count && elapsedTime >= timeThresholds[step])
{
thingsToDo[step].Invoke();
++step;
}
}
Thank you! The code is really smart and works well, fits perfectly with what I have to do. I hope with the practice of being able to obtain similar solutions more easily.