I am wanting to lerp the variable that controls my animations speed so it transitions fluidly in the blend tree.
void Idle()
{
_agent.SetDestination(transform.position);
//Something like the following line
_speed = Mathf.Lerp(0.0f, _speed, -0.01f);
_animationController._anim.SetFloat("Speed", _speed);
}
I'v read that you can't lerp negatives, so how do I do this?
I think you're using Lerp bad.
As written in Unity Documentation (http://docs.unity3d.com/ScriptReference/Mathf.Lerp.html), you should pass 3 floats, the minimum as first argument, the maximum as second and the time as third.
This third should be beetwen 0 and 1.
Aside from that, you can always make the number negative after lerping it.
Some examples :
In case you want from -10 to 10, lerp from 0 to 20 and then substract 10.
float whatever = Mathf.Lerp(0f, 20f, t);
whatever -= 10f;
In case you want from 0 to -50, lerp from 0 to 50 and then make it negative.
float whatever = Mathf.Lerp(0f, 50f, t);
whatever = -whatever;
The t value in a lerp function between a and b typically needs to be in the 0-1 range. When t is 0, the function returns a and when t is 1, the function returns b. All the values of t in between will return a value between a and b as a linear function. This is a simplified one-dimensional lerp:
return a + (b - a) * t;
In this context, negative values of t don't make sense. For example, if your speed variable is 4.0f, the result of lerp(0, 4, -0.01f) would be:
0 + (4 - 0) * -0.01
which returns -0.04.
The simplest way to solve this issue is to simply flip a and b instead of trying to use a negative t.
_speed = Mathf.Lerp(_speed, 0.0f, 0.01f);
Another suggestion would be to use Mathf.SmoothStep and store the original speed instead of applying the function on the constantly changing _speed to get a really smooth transition.
Well, you cannot actually.
A psuedo-codish implementation of a Lerp function would look like this:
float Lerp(float begin, float end, float t)
{
t = Mathf.Clamp(t, 0, 1);
return begin * (1 - t) + end * t;
}
Therefore, any attempt to give a t value outside of [0, 1], ie. an extrapolate attempt, would be clamped to the valid range.
Related
I have created a helper to PingPong from 1 to 0, but I'm having a hard time inverting this, so that the value goes from 1 to 0.
Below you can see the code, I'm currently using. I'm also not sure if this is even possible.
_lerpPulse = PingPong(Time.time * 0.5f, 0f, 1f);
And the helper
float PingPong(float aValue, float aMin, float aMax)
{
return Mathf.PingPong(aValue, aMax - aMin) + aMin;
}
Thanks in advance!
Mathf.PingPong creates a graph like this
So, to begin at a peak, you can add the distance to the peak along the x axis to the time parameter, which will be sqrt(2)/2 * the length, or 0.707 * length
float PingPong1To0(float aValue, float aMin, float aMax)
{
float offset 0.707f * (aMax - aMin); // sqrt(2)/2
return Mathf.PingPong(aValue +offset, aMax - aMin) + aMin;
}
Should hit the falling side of that triangle
So I am currently creating movement for a character and all is well except diagonal movement is doubled because it is obviously combining vertical and horizontal movement. Now I did try normalizing the Vector3, but that results in a delayed stop for the character. According to other forums I read, I think it's because it should only normalize when it is greater/less than -1/1 but I don't know how to setup this constraint. Please help!
forwardInput = Input.GetAxis("Horizontal");
horizontalInput = Input.GetAxis("Vertical");
Vector3 movement = new Vector3(horizontalInput, 0, forwardInput).normalized * speed * Time.deltaTime;
transform.Translate(movement);
Problem with always normalizing is that you move with the same speed no matter how far the input is pressed.
This is no problem on a PC with keyboard input which is either 0, -1 or 1 but will not work as expected if e.g. using a controller since it will also round up the value in case you normalize if the original input vector's magnitude is smaller then 1.
So yes you should normalize only in case the magnitude of the input vector exceeds 1 e.g. when pressing in two directions at the same time in order to maintain a certain maximum speed. In order to not type redundant code I would rather separate the vector and assignment in different variables and use Vector3.Normalize instead:
forwardInput = Input.GetAxis("Horizontal");
horizontalInput = Input.GetAxis("Vertical");
var inputVector = new Vector3(horizontalInput, 0, forwardInput);
// note that a magnitude is always positive, there is no -1
// if magnitude > 1 then implicitely also sqrMagnitude > 1 and the other way round
// sqrMagnitude is faster to access then magnitude and for this check
// here provides the same result
if(inputVector.sqrMagnitude > 1) inputVector.Normalize();
var movement = inputVector * speed * Time.deltaTime;
transform.Translate(movement);
I am performing the following, but instead of zRem having the expected value of zero I get 2.384186E-07:
Vector3 t = this.transform.position - _startPosition;
float xRem = t.x % 1;
float zRem = t.z % 1;
In this instance:
this.transform.position = 2.5, 0, 3.5
_startPosition = 1.5, 0, 1.5
xRem is correct, but zRem have the value 2.384186E-07.
Any suggestions on how to fix this?
UPDATE #1:
When using the values above it should not enter this block, but because of zRem it does.
if(!Mathf.Approximately(xRem, 0f) || !Mathf.Approximately(zRem, 0f))
{
return;
}
Well, mod is not failing... Float point arithmetics always involve some level of precision/error.
I know, Mathf.Aproximately is meant to take ilthis into account, but Unity have its own Epsilon value for comparing floats and, guess what, it's value isn't documented.
https://docs.unity3d.com/ScriptReference/Mathf.Epsilon.html
(Maybe it is system dependent, according to the representation model of float values. Maybe it's IEEE conformant, I don't know)
Thing is: you should define what threshold use that conforms with your game logic, something like this:
if(xRem <= threshold)
Or
if(Mathf.abs(xRem) <= threshold)
im trying to move a object in unity between 2 points, and at the moment it kinda works strange, i read the documentation and it says that the object begin point is (0,0,0) so my object goes under my other mesh that i have there, and the end point i can actually control, in my case it is 10, i want the object to move between 1.5 and 10(not 0 to 10)
i have this
void Update () {
transform.position = new Vector3(transform.position.x,Mathf.PingPong(Time.time,10.0f), transform.position.z);
}
when i try to put speed on the ball doing this:
void Update () {
transform.position = new Vector3(transform.position.x,Mathf.PingPong(Time.time,10.0f) * 10, transform.position.z);
}
the object does not colide and goes back at the end point it just stop looping and never came back how can i correct this 2 problems?
If your object has a collider, I suggest you move it via its Rigidbody rather than its Transform, to avoid potential collision issues. Try this:
public float MinY = 1.5f; // y position of start point
public float MaxY = 10f; // y position of end point
public float PingPongTime = 1f; // how much time to wait before reverse
public Rigidbody rb; // reference to the rigidbody
void Update()
{
//get a value between 0 and 1
float normalizedTime = Mathf.PingPong(Time.time, PingPongTime) / PingPongTime;
//then multiply it by the delta between start and end point, and add start point to the result
float yPosition = normalizedTime * (MaxY - MinY) + MinY;
//finally update position using rigidbody
rb.MovePosition(new Vector3(rb.position.x, yPosition, rb.position.z));
}
Here you have a better control on the distance to travel, and the speed.
Actually I didn't get exactly what are the problem you faced. But don't forget here and in your try, that you are directly modifying the position of the object, not adding forces or else.
Hope that helps you.
I think you simply misunderstood how the Mathf.PingPong method works :
first argument t is the value you want to "clamp" between 0 and the given length : this is were you want to put the Time.time as you did since this value will increase over time and therefore perpetually oscillate. If you want to increase/decrease the oscillation speed you have to multiply it.
second argument length is the max value of the "clamp" : if you want to increase/decrease the distance (in your case) you have either set it to 0 and multiply the whole Mathf.PingPong(...) by a value or directly give it the wanted value (both implementations will have a different effect.
Mathf.PingPong(Time.time * speed, 1.0f) * value : speed will affect the oscillation speed / value will affect the max value reached AND the speed / time to complete the oscillation (back and forth) will remain the same as value changes and decrease as speed increases
Mathf.PingPong(Time.time * speed, value) : speed will affect the oscillation speed / value will affect the max value reached BUT NOT the speed / time to complete the oscillation (back and forth) will increase as value increases and decrease as speed increases
About your other problems :
If you want to move your object between 1.5 and 10 you have to write something like this :
transform.position = new Vector3(transform.position.x, 1.5f + Mathf.PingPong(Time.time, 10.0f - 1.5f), transform.position.z);.
Also if you want to detect collision, avoid setting position manually as it will mess up with Physics and cause weird behaviors. Best way to move your object while keeping physic working is to do as #Heldap said using Rigidbody.MovePosition.
I'm sitting here and trying to resolve an issue I have, with alternating between 0 and 1 of a variable.
Basicly, I want to do something like this:
float distance = 32f;
float maxDistance = 32f;
float clampedDistance = Math.ClampPresentableValue(distance, maxDistance);
The variable "clampedDistance", would receive the clamped value from the math method. "ClampPresentableValue" should in this case, be able to take the "distance" value, and calculate, where it is in the "0 to 1" timeline, in comparison to the maxDistance.
In this case, since "distance" is the same as "maxDistance", the clamped value would be 1.0f. But if we cut "distance" down to 16f, the clamped value would present 0.5f, in the "clampedDistance" variable.
What is something like this called? Does it have a name, or is it just an algorithm that i'd have to build myself?
It should probably be called 'normalize' or something like that. If I understood you correctly, you should simply do this:
float normalizedDistance = distance / maxDistance;