Vector3 never seems to be equal - unity3d

I have a fairly simple function that moves a camera to a destination:
void MoveToward(Vector3 destination, float speed)
{
// so we only want the movement to start when we decide
if (!started)
return;
Debug.Log("Moving to :" + destination);
Debug.Log("Currently at: " + transform.position);
// Move the camera into position
transform.position = Vector3.Lerp(transform.position, destination, speed);
if (transform.position.Equals(destination))
{
started = false;
Debug.Log("Arrived!");
}
}
The movement works great. However, the if statement at the end never evaluates to true. I also tried to do:
if (transform.position == destination)
{
started = false;
Debug.Log("Arrived!");
}
That also never works, even though the '==' operator is supposed to evaluated 'approximate' equality.
The Debug log earlier in the function seems to show matching values (screenshot attached).
Any guidance is appreciated!
Like I mentioned, checking the values in the debug log, tried using the equality operator, as well as the Vector3.Equals function. None of which seem to ever evaluate to true.
While experimenting, I found that I can change the 'speed' value, and it will cause the equality to evaluate as true. At first, I was using .03f as the speed. Changing it to .1f causes it to eval to true. The bigger the number, the faster it gets there, but .03 never seems to get there.
Also, weirdly, changing the order of the Lerp and the Debug.Log statements seems to cause the movement to change speed, even when the speed value remains the same.

Oh, no, not another misuse of the Lerp function! Lerp moves from value A to value B by a given number, so if I put one and three in, with a value of 0.3, it would move 30% of the way to B giving me 1.6. The issue is when you update A. If you now set A to 1.6 and ran it again, it would move 30% again from the new value, giving 2.02! Each time it will move a smaller and smaller amount, theoretically never reaching it, although floating point numbers can be weird.
Solution 1: Don't change A or B, but increase the lerp amount. With the same example as before, lerping from 1 to 3, it would start the same with a lerp of 0.3 going to 1.6. Next, instead of changing A, change the lerp amount to 0.6. Now lerping from 1 to 3 with 0.6 will give 2.2, the expected amount.
Solution 2: Use MoveTowards. This one literally moves towards the value by the amount specified in the third parameter. If I give it 0.3 it will give 1.3. Next, it would again move by exactly 0.3 to 1.6. This will repeat, 1.9, 2.2, 2.5, 2.8, until it reaches the destination 3.
I would suggest solution two when possible, as you can move the end goal in real time and it will keep running smoothly, and it is easier to give it an exact speed, although if you want it to take an exact amount of time, and the target isn't changing, Lerp is better.
Also, make sure you multiply your speed with the timestep. If this is in Update(), that would be Time.deltaTime, and if it is in FixedUpdate(), that would be Time.fixedDeltaTime.
TLDR: Use .MoveTowards() instead for the easy fix, which takes in an amount and moves by that. Multiply speeds by the timestep for consistent movement. Lerp isn't meant to be used that way, read docs for additional info.
Mathf.Lerp Vector3.Lerp Mathf.MoveTowards Vector3.MoveTowards
Edit: You can also google SmoothDamp if you want a smooth motion, or you can fix how you use Lerp and raise it to some power to get a fade in or out.

Related

Object maintains changes to its Y position after getting reset

I have been programming a deeper version of Pong using skills.
One of the skills is that the player will make the other player's paddle stop, and instead the enemy will start moving its goal.
I start moving the goal with this method. The method is called in the FixedUpdate.
private void moveGoal(string vertical, Vector3 nextPosition)
{
nextPosition += speed * Time.fixedDeltaTime * Input.GetAxis(vertical) * Vector3.up;
nextPosition.y = Mathf.Clamp(nextPosition.y, goalMinY, goalMaxY);
rb.transform.position = nextPosition;
}
We have tried doing it in the Update and using the Time.deltaTime, but the result is the same.
We recently changed to "rb.transform.position" from "rb.MovePosition(nextPosition)" because the problem was way worse.
The position is reset with a method inside the skill's script where we have saved the base position of the goal, and once the skill gets deactivated it automatically reset the goal's position to its base position.
The problem is that if the goal starts in the Y position 1.4, after it has been reset the y position changes slightly, for example going from 1.4 to 1.25.
We do not understand why it is moving even though the position we set it to is always the same.
I am sorry if the post sounds confusing, but the problem itself is very confusing and very difficult to explain.
Sorry if I am misunderstanding your issue. Could it be that you reset the position of the goal but within the same frame it executes moveGoal() once, setting it slightly off your original position? Goodluck.

When do you multiply by Time.deltaTime in Unity?

There seems to be a lot of confusing/conflicting advice out there about when you should or should not multiply a quantity by Time.deltaTime. So I was wondering, as it pertains to the Unity physics system, when should you multiply by Time.deltaTime?
I understand that Time.deltaTime is used to make certain actions framerate independent, but there are some situations where it isn't clear whether an action is framerate independent. For instance:
Doing rigidbody.velocity += acceleration*Time.deltaTime; in FixedUpdate. Since FixedUpdate runs at a constant timestep, does this make the multiply by Time.deltaTime unnecessary?
Doing rigidbody.AddForce(force*Time.deltaTime, forceMode);. How do the various ForceModes effect this?
I've seen solutions to individual situations, but it would be nice if there were a simple intuition which could address all of these situations.
The intuition
Multiplying by Time.deltaTime is used to make an instantaneous operation act in a continuous (or "smooth") way.
An instantaneous operation will cause a certain quantity to "jump" to a different value. The following operations are instantaneous:
Rigidbody.[position|velocity|rotation|angularVelocity] += x;
Rigidbody2D.[position|velocity|rotation|angularVelocity] += x;
Rigidbody.Add[Force|Torque](x, ForceMode.[Impulse|VelocityChange]);
Rigidbody2D.Add[Force|Torque](x, ForceMode2D.Impulse);
All the above operations cause a quantity to instantly jump by x, irrespective of the length of the frame.
In contrast, the following operations are continuous:
Rigidbody.Add[Force|Torque](x, ForceMode.[Force|Acceleration]);
Rigidbody2D.Add[Force|Torque](x, ForceMode.Force);
Rigidbody.velocity = x; (continuous from the perspective of Rigidbody.position. i.e. setting the velocity will not make Rigidbody.position suddenly jump to a new value)
All the above operations are applied over the course of the frame (at least conceptually this happens; what the physics system does internally is out of the scope of this answer). To illustrate this, Rigidbody.AddForce(1, ForceMode.Force) will cause a force of 1 newton to be applied to an object for the entire frame; there will be no sudden jumps in position or velocity.
So when do you multiply by Time.deltaTime?
If you are using a continuous operation, you should almost definitely not be multiplying by Time.deltaTime. But if you are using an instantaneous operation, the answer depends on if the operation is being used in a continuous way.
Example 1: Explosion
void Explode() {
rigidbody.velocity += explosionAcceleration;
}
Here you should not be multiplying by Time.deltaTime since Explode() gets called just once. It is not meant to be applied over a series of frames.
Example 2: Moving
void Update() {
rigidbody.position += velocity * Time.deltaTime;
}
Here you do have to multiply by Time.deltaTime because the object is supposed to move continuously over time, and you are also using an instantaneous operation. Note that this could be replaced with a continuous operation, and remove the need for multiplying by Time.deltaTime:
void Update() {
rigidbody.velocity = velocity;
}
Although this isn't entirely equivalent to the original, since it ignores the previous value of rigidbody.velocity.
Example 3: Accelerating
void Update() {
rigidbody.AddForce(acceleration*Time.deltaTime, ForceMode.VelocityChange);
}
Here you should be multiplying by Time.deltaTime because you want the velocity to increase at a consistent rate frame by frame. Note that this is precisely equivalent to:
void Update() {
rigidbody.AddForce(acceleration, ForceMode.Acceleration);
}
This code applies the acceleration over the course of the whole frame. This code is also (in my opinion) cleaner and easier to understand.
What about FixedUpdate?
Being in FixedUpdate does not effect any of the above advice. Yes, you could theoretically get away with never multiplying by Time.deltaTime since the time between frames would always be the same. But then all your units would have to be dependent on the fixed frame rate. So for example if you wanted to move at a rate of 1 m/s with 60 frames per second, you would have to add 1/60=.01666 to the position each frame. And then imagine what happens if you change your fixed timestep. You would have to change a bunch of your constants to accommodate.
Executing code in FixedUpdate does not suddenly make that code framerate independent. You still have to take the same precautions as in Update.
As a side note, you do not need to replace Time.deltaTime with Time.fixedDeltaTime inside FixedUpdate because Unity already does this substitution.
Conclusion
Only multiply by Time.deltaTime if you want an instantaneous operation to act smoothly over a series of frames.
Many times, you can avoid using Time.deltaTime by using continuous operations, which are often more intuitive (see examples 2 and 3). But this of course depends on the context.
A simple way to think about this is to determine:
Are objects' transforms manipulated directly?
When an object is being moved directly via its transform.position and transform.rotation components, manipulation of the transform should occur in Update(), which runs once per drawn frame. The developer should build their game with the expectation that the Update/frame rate varying between zero and the game's maximum frame rate. The way to accomplish this is by factoring in the time between now and previous frame into the movement (step) for each update/frame.
Thus, manipulations to the transform.position and transform.rotation should factor in Time.deltaTime and should occur within Update().
Are objects being manipulated with physics?
In this case, forces and torques should be applied by calling Rigidbody.AddForce() or Rigidbody.AddTorque() in FixedUpdate(). FixedUpdate() can be expected to occur at a fixed/guaranteed rate, which Unity defaults to 50 times per second (this can be adjusted within the Physics settings of your game project).
To complicate things a bit, when AddForce() and AddTorque() are called with ForceMode.Force (default) or ForceMode.Acceleration, the value provided for the force or torque parameters will be interpreted as amounts for one entire second, so these functions will adjust the value (a force/torque or acceleration/angular acceleration) for one fixed time step (i.e., x 0.02s with the default Unity Physics fixed update rate).
In case you are curious about ForceMode.Impulse or ForceMode.VelocityChange, these will interpret the force or torque as the amount to apply within that fixed time step (i.e. the value will not be adjusted with respect to time).

Addforce changes with framerate

I have a line that is applying force to the player. The force is applied in an Update() while the player is in the Roll animation state.
if (anim.GetBool("isRolling") == true && anim.GetBool("IsGrounded") == true && canRoll == false)
{
rb.AddForce(transform.forward * rollLength, ForceMode.Force);
}
I am targeting two devices, one with high framerate and one with low framerate. On the one with low (30 fps) framerate, it works fine, but on the high framerate (in the 100s) the player goes too far too fast. I have read that Time.deltaTime will divide the force, which doesn't help me.
What can I do to fix this issue?
Addforce doesn't add Force in physical sense as much as it adds energy: you should control amount and frequency byt Time.deltaTime which makes single call time-dependent, but also you should keep in mind that FixedUpdate exists - it works like a classic Update but it's guaranteed to have constant time in between each calls (equal Time.fixedDeltaTime). Generally speaking if you manipulate phisics in each frame you most likely want to use FixedUpdate instead of Update
But honestly I would considered if addForce is good idea for a rolling mechanic in the first place: I feel like it would be better idea to use Rigidbody.velocity or Rigidbody.Move()
As said above: "AddForce" doesn't really adds force, but energy instead so you should scale it using Time.deltaTime
When doing physical calculations in unity it is recomended to do them inside FixedUpdate, as it is guaranteed to have constant rate of activation which allows you to avoid certain problems that are often for physics with even small framerate fluctuation and correct usage of Time.deltaTime

How exactly is addforce impulse calculacted?

I'm having a bit of a problem that I have been trying to figure out for the last ~5 days, basically, I want an object to move by a specific amount using AddForce, for example, lets say 1 unit, however, when I use this snippet of code
body.AddForce(new Vector3(1,0,0), ForceMode.Impulse);
instead of moving it by 1 unit, so that the position is
1,0,0
It moves it by
0.03291207,0,0
so I realized that there is a calculation here, so I thought maybe for every 1 velocity, it moves it by 0.0329...., so I figured if I were to multiply the velocity by around 30, however, if I put
body.AddForce(new Vector3(30,0,0), ForceMode.Impulse);
, but now it moves it by
37.92695,0,0
, so I was really confused. So after making a spreadsheet and then copying and pasting different velocities and how they work, I finally figured it out. so it works a something a bit like this :
basically, there are 3 things, the input value [which we will call X], the velocity, and the position. the Velocity starts outs as the X, and every frame its decreased by - 0.2355
the position starts out as whatever position it is, and then there is a speed value, lets call it Y, now Y starts out as X divided by 100 and multiplied by 2, so for example if X is 1, Y would start out as 0.02, then, ~0.0048 is removed from Y, so now it's 0.0152, and then every frame, the position is increased by the Y value, and also every frame, Y is being decreased by ~0.0048, ~0.0048 being the friction [I think].
and now that I knew how it worked, I could reverse engineer, and I did! so I figured out that to get the object to move by 1 unit, I needed to input around 5.02 velocity. So, you might be wondering if I figured it out, why am I posting it here? well, the problem arises when I try to move it on the Z-axis at the same time, like
body.AddForce(new Vector3(1,0,1), ForceMode.Impulse);
now it moves it by on both axis by
0.0500636, 0, 0.0500636
instead of
0.03291207,0,0.03291207
. So this really made me confused, so then I made a spreadsheet and then copied and pasted different velocities and how they work. And it turns out the formula is still the same, however, 0.2355 and 0.0048 are changed, for example when it's
body.AddForce(new Vector3(1,0,1), ForceMode.Impulse);
, 0.0048 is actually 0.00332966 so Y is being decreased by 0.00332966 every frame, but if there are 2 different numbers, then, they both have different 0.0048's, for example, if it's
body.AddForce(new Vector3(1,0,2), ForceMode.Impulse);
. for 1 the value is 0.00210584 meaning Y gets decreased by 0.00210584 every frame, but for 2 in the same vector, 0.00421168 is the magic number, meaning Y is decreased by 0.00421168 every frame.
And that's where I'm stuck, I can't figure out where these numbers are coming from. I tried dividing it, multiplying it, subtracting and adding and I just cant figure it out. So I would really appreciate help from the physics experts here. Keep in mind that I don't know that much about physics and only know a bit about algebra and stuff like that, so I have no idea what the correlations are. If anyone needs it, here is the table I made showcasing every "magic number" from 1 to 6, the colored squares are squares that are quite similar
Sorry if this post was a bit confusing and sorry if I'm not supposed to ask this here, but I'm not sure where else on stack could i ask this, this whole topic is a bit confusing so I'm not sure if I explained it well enough, and I'm a bit tired, so if you didn't understand anything just leave a comment and I will try to answer it, Thanks in advance for any help :)

Lerp with Time.deltaTime

I have a question about Lerp. So I know that lerp helps you to move your object like:
void update(){
transform.position = vector3.lerp(start.position,end.position, (Time.time / 1000));
}
this will get your object to your endposition.
But if you have this code:
void Update(){
transform.position = Vector3.Lerp(transform.position,
destination.position,
speed * 3.0f * Time.deltaTime);
}
How is it possible that your object arrives at your destination, the 3th parameter of lerp has to reaches slowly 1 so your objects arrives at your destination. But "speed" , "3.0" , "Time.deltaTime" will always be the same, so how is it possible that your object arrives at your destination?
So the big question: Is it possible to do the lerp with some variables, which have always the same value and with Time.deltaTime?
Now, because of the different comments etc. I don't know exactly how lerp works, i have to possibilities:
1.) First i thought it works like this:
Vector3.lerp(a,b,c)
The c value has to change every frame to move the object. If the c value is 0.2 your object will moved 20% of the way and if the c value doesn't change the object will always be on 20% of the way. So the get the object moved fluently your c value have to change every frame a little so you c value will go from 0 to 1 and so is your object going from start to destination.
Or is it like this
2.) Because of several comments i thought lerp works like this
Like the comments say, the c value doesn't have to change the value, becaue if you have c = 0.2 you will pass 20% of the way and the next frame, if c is still 0.2 you will pass 20% of the remaining way and so on.
So is it lerp working like 1(you have to change c) or is it working like 2(you don't have to change c)
The distance between your transform position and the destination is an exponential decay. The distance shrinks by (1 - speed) every frame (given that speed is less than 1). Say your game is supposed to run at 60FPS. If for whatever reason the frame rate drops to 30FPS, the deltaTime is gonna be twice as big and you’re supposed to execute the Lerp 2 times. In such case, the distance will shrink by (1 - speed) then (1 - speed) again yielding a result of (1 - speed)^2 shrinkage. From this, you can generalize that the shrink amount of the distance is (1 - speed) ^ (deltaTime / baseDeltaTime) with baseDeltaTime being the deltaTime the game is supposed to run at i.e. 1/60 (for 60FPS).
To put in code:
transform.position = Vector3.Lerp(transform.position, destination.position, 1 - Mathf.Pow(1 - speed * 3.0f, Time.deltaTime * 60));
The object reaches the goal because your start position is the current position, and after lerping, you set the position of the object to the resulting position of Lerp. If you change your starting position to a normal Vector3 it would Lerp to "speed * Time.deltaTime * 3f"
I guess you didn't understand that how lerp works in unity. I will recommend you this Article of Robbert How to Lerp like a pro.
I see this sort of thing far too often:
transform.position = Vector3.Lerp(startPos, endPos, Time.deltaTime);
The person posting it is usually convinced that Vector3.Lerp is
“broken”, but the real problem is that they’re not using it correctly.
Lerp, short for “linear interpolation” does one very simple thing:
given two values, x and y, it returns a value that is t percent
between them. If you expect the output to change, the arguments you
pass in need to reflect that!
In the example above, it doesn’t make sense to just pass in
Time.deltaTime, because that’s only the time that passed during the
most recent frame. If your game is running at a constant 50fps, that’s
always going to be 0.02.
myLocation = Mathf.Lerp(myLocation, myDestination, 0.02)
If you are storing the return of the Lerp function into a variable and then also using that same variable as the minimum value in that same Lerp function, then the min value is getting bigger and bigger everytime the function is called.
So, even though you're not changing T, you're changing the starting value and thus, the stored value gets closer and closer to the max value.
It will accelerate very quickly initially and then slow down the closer it gets to the max value. Also, the max value will either never be reached or take an extremely long time.
(See https://gamedev.stackexchange.com/questions/149103/why-use-time-deltatime-in-lerping-functions)
There are two common ways to use Lerp:
1. Linear blending between a start and an end
progress = Mathf.Clamp01(progress + speedPerTick);
current = Mathf.Lerp(start, end, progress);
2. Exponential ease toward a target
current = Mathf.Lerp(current, target, sharpnessPerTick);
Note that in this version the current value appears as both the output and an input. It displaces the start variable, so we're always starting from wherever we moved to on the last update. This is what gives this version of Lerp a memory from one frame to the next. From this moving starting point, we then then move a fraction of the distance toward the target dictated by a sharpness parameter.
This parameter isn't quite a "speed" anymore, because we approach the target in a Zeno-like fashion. If sharpnessPerTick were 0.5, then on the first update we'd move halfway to our goal. Then on the next update we'd move half the remaining distance (so a quarter of our initial distance). Then on the next we'd move half again...
This gives an "exponential ease-out" where the movement is fast when far from the target and gradually slows down as it approaches asymptotically (though with infinite-precision numbers it will never reach it in any finite number of updates - for our purposes it gets close enough). It's great for chasing a moving target value, or smoothing a noisy input using an "exponential moving average," usually using a very small sharpnessPerTick parameter like 0.1 or smaller.