#Float behaving weirdly

1 messages · Page 1 of 1 (latest)

south cedar
#

Sorry for the title, I wasn't sure how to describe the problem in a short way. Basically, I have a slider connected to a float which is the stamina you see on the slider(called tempStamina) and I have another float, which is the actual stamina(called currentStamina). I have another script basically saying, that if you press space the real stamina gets subtracted by 2 and I the stamina script says:
if(tempStamina < currentStamina){
tempStamina -= 0.1f;
}
My problem is that when I press space in game the tempStamina doesn't go down until it's 8 but it goes down until it's 7.999993 (it's the same every time). I wanted to ask if anyone knew why this is happening and could help me fix it? I've tried rounding the number with Mathf.Round(tempStamina); in Update() but it didn't work for some reason. Btw the if() is also in Update

frigid gate
#

What you are experiencing is called "floating point imprecision".
The System.Single data type (aliased as float for convenience) sacrifices accuracy for a larger value range. That is also why you should never directly check equality between float values - even if they appear to be the same, they may just be off a bit - literally - and not return the expected result.

In this case, you likely don't need complete precision. But when you do, consider using a double or decimal instead (for reference, see the MSDN article on floating point numeric value types).

#

That being said, doing fixed-value additions or subtractions inside Update to create change over time is not a good idea, because you will end up with inconsistent results:
Assume you have a variable with a value of 60, and you decrease it by 1 inside Update.
For a player running the program at 60 fps, it will take 1 second until the variable reaches 0.
For a player running the program at merely 30 fps, it will take twice as long, because the Update method only runs once per frame.
To make changes over time consistent, you should factor in Time.deltaTime. This [FAQ entry](#faq_unity message) describes it a little more in depth.

gaunt stag
#

Are you aware of floating point errors

#

Wait zenvin beat me lol

#

also does it really need to be exactly 8

south cedar
#

yeah, because stamina is something the player is supposed to have and if it always decreases by more than 2 then you can dash less times than I want the player to be able to dash

#

cause I‘m using stamina to dash

south cedar
#

So I tried using ints now and it works (it now doesn't go down by 0.1 but by 1 and the max isn't 10 anymore but 100) but the slider doesn't go down. In update I have staminaSlider.value = tempStamina; but the slider doesn't change when temp slider goes down.

#

nvm it worked

gaunt stag
#

It doesn't sound like it needs to be exactly 8

south cedar
#

It doesn't matter anymore I was able to fix it by using ints instead of bools

#

I mean floats

#

not bools

#

sorry

gaunt stag
#

did you factor in time.delta time like zenvin suggested?

#

i don't think you did

south cedar
#

I think so

#

let me check rq

#

it seems like I didn't

#

but I'm also unsure on how since I can't really multiply it by Time.deltaTime since they're ints

gaunt stag
#

one solution is not to use ints

south cedar
#

but if I don't use ints I won't be able to recognise when tempStamina and currentStamina are the same so I know when I'm able to refill stamina

gaunt stag
#

i think you are limiting yourself because of an unoptimal way of doing something

#

as I mentioned before, do you need it to be exactly 8

south cedar
#

I think so

#

When I get back I can try to do it without it being exactly 8

#

even though idk if it's going to be easy

#

because I'm still a beginner and don't know a lot

#

if(!staminaIsBeingUsed && currentStamina < maxStamina && tempStamina < maxStamina && currentStamina == tempStamina)
{
startRefillTimer += Time.deltaTime;

        if(startRefillTimer >= endRefillTimer)
        {
            staminaIsRefilling = true;
            startRefillTimer = 0f;
        }
    }

I think I need it to be 8 to be able to do this

gaunt stag
#

How you've coded it yes, it requires that it is exactly 8

#

But are there other ways to achieve the behavior you want?

south cedar
#

Could you tell me another way? I‘m unsure on how to do it differently

gaunt stag
#

for sure!

#

so instead of using ==, you could use >=. do you understand what how this would work?

#

in general, due to floating point imprecision its a bad idea to use == to compare floats

south cedar
south cedar
#

?

#

or how would I implement Time.deltaTime

south cedar
gaunt stag
#

yes, you would need to change things back to floats in order to use time.deltatime (technically there are cursed ways around this but that's another story)

south cedar
#

and 0.1f * Time.deltaTime is correct?

gaunt stag
#

what is tempStamina

gaunt stag
south cedar
#

so when currentStamina get‘s reduced you don‘t see it but that way tempStamina knows how much to go down

south cedar
#

I‘ll try it out once I get home

south cedar
#

I could try sending the whole script if that helps but idk

gaunt stag
#

why don't you want the stamina bar to visually go down when its being used?

south cedar
#

because if it goes down by 2 it doesn‘t go down smoothly but it jumps down from 10 to 8

#

but I want it to look smooth

#

so I have a variable that jumps to 8 and another one that follows by becoming smaller by .1 very often

gaunt stag
#

so you want the stamina bar to go down smoothly?

south cedar
#

yes

#

and that was the only way I found that also made it work

gaunt stag
#

by using time.deltatime, your variable already goes down smoothly

south cedar
#

so if I just multiply by Time.deltaTime everytime I subtract from currentStamina it goes down smoothly?

#

like if I say currentStamina -= 2 * Time.deltaTime; it would go down smoothly?

gaunt stag
#

do you understand the origin of time.deltatime and why it is useful?

south cedar
#

I don‘t really

#

I only know it‘s to make everything the same with different fps and that it marks the time basically

gaunt stag
#

[]deltatime you can read this

unkempt gulchBOT
#

Time.deltaTime is the amount of seconds it took for unity to calculate and render last frame. Let's say your game runs at a constant 100 frames per second, then Time.deltaTime will be 0.01f every frame. But games usually don't run at a constant frame rate so Time.deltaTime compensates for that.

For example:

private void Update()
{
    transform.position += new Vector3(0f, 0f, 10f);
}
private void Update()
{
    transform.position += new Vector3(0f, 0f, 10f) * Time.deltaTime;
}

In the first example; if the game runs at 100 fps, the object will move twice as fast compared to if the game ran at 50 fps.
But let's look at the second example:

If the game is running at 100 fps: the object will move by (10 * 0.01) 0.1 units every frame, therefore moving (0.1 * 100) 10 units every second.
If the game is running at 50 fps: the object will move by (10 * 0.02) 0.2 units every frame, therefore moving (0.2 * 50) 10 units every second.
If the game is running at 20 fps: the object will move by (10 * 0.05) 0.5 units every frame, therefore moving (0.5 * 20) yet again 10 units every second.

south cedar
south cedar
gaunt stag
#

games are kind of a trick right

#

objects never move smoothly, we always increment their position or value or whatever by some value. but if we do it by a small enough value, and do it often enough, we can trick our brains into thinking of smooth behavior

south cedar
#

yeah I know

#

that‘s what I meant

#

sorry, I meant to say that

#

that‘s why I decrease tempStamina by 0.1

gaunt stag
#

to clarify, you're already decreasing the stamina by a small value every frame/every time update calls, that makes it seem smooth

#

but by multiplying by time.deltatime, you're making sure that the decrease is framerate independent (the stamina does not decrease faster or slower depending on your fps)

south cedar
#

yes, I understand that

gaunt stag
south cedar
#

but, like, how do I add Time.deltaTime so it is frame independant

#

like, where do I multiply by Time.deltaTime

gaunt stag
#

you multiply wherever there is a framerate dependent operation going on

#

just think to yourself, "if the user has a really high fps, is that going to affect this calculation?"

#

if so, you should multiply by time.deltatime

#

for example, before you had (in update) tempStamina -= 0.1; if the user has a high fps... what happens?

south cedar
#

yeah, and I know I have to do this with my stamina going down/back up

south cedar
gaunt stag
south cedar
#

yeah, but I‘m unsure where exactly in the code

#

would it be behind the .1?

#

like tempStamina -= 0.1f * Time.deltaTime;

#

?

gaunt stag
#

thats one way you can do it

#

what other ways were you thinking of

south cedar
#

that‘s the only one that comes to mind

gaunt stag
#

alright ya that's what i would do

south cedar
#

ok, tyvm

#

and sorry for wasting so much of your time

gaunt stag
#

haha its no waste that's what we are here for

south cedar
#

Ok, again, thanks a lot!

#

Have a great day :D

gaunt stag
#

you're welcome! you as well