- Home /
Trying to set up a lerp position system for the camera and failing...
Well this has had me pulling my hair out all day. So I've given up and will post it here.
The goal; ( set up a state system for the camera which will tell it which position to lerp too, depending on the state it's in)
What's happening; works ok, except every other state switch camera "snaps" to the end position with no lerp. And the transforms never seem to hit the goal position I've set in code. ex. - instead of x 15. it will go to x 14.9997 and stop. I don't understand that.
the code;
function Update ()
{
if ( moveCamLeft )
{
MoveCamLeft ();
}
if ( moveCamRight )
{
MoveCamRight ();
}
if ( moveCamCenter )
{
MoveCamCenter ();
}
}
function SetMainCamState ()
{
switch ( cameraState )
{
case MainCamState.LeftScreen :
hudOn = false;
mudHudOn = false;
moveCamLeft = true;
moveCamRight = false;
moveCamCenter = false;
//changeCam = false;
break;
}
switch ( cameraState )
{
case MainCamState.CenterScreen :
hudOn = false;
mudHudOn = false;
moveCamLeft = false;
moveCamRight = false;
moveCamCenter = true;
//changeCam = false;
break;
}
switch ( cameraState )
{
case MainCamState.RightScreen :
hudOn = false;
mudHudOn = false;
moveCamLeft = false;
moveCamRight = true;
moveCamCenter = false;
//changeCam = false;
break;
}
}
function MoveCamLeft ()
{
targetPosition = Vector3 (-11.5, 0, -5);
while (transform.position != targetPosition)
{
transform.position = Vector3.Lerp (transform.position, targetPosition, Time.deltaTime * camSpeed);
yield;
if (transform.position - targetPosition == 0)
{
print ("breaking left");
moveCamLeft = false;
break;
}
}
}
function MoveCamCenter ()
{
targetPosition = Vector3 (0, 0, -5);
while (transform.position != targetPosition)
{
transform.position = Vector3.Lerp (transform.position, targetPosition, Time.deltaTime * camSpeed);
yield;
if (transform.position - targetPosition == 0)
{
print ("breaking Center");
moveCamCenter = false;
break;
}
}
}
function MoveCamRight ()
{
targetPosition = Vector3 (11.5, 0, -5);
while (transform.position != targetPosition)
{
transform.position = Vector3.Lerp (transform.position, targetPosition, Time.deltaTime * camSpeed);
yield;
if (transform.position.x - targetPosition.x == 0)
{
print ("breaking right");
moveCamRight = false;
break;
}
}
}
As you can see I've been trying to break the lerp, but am failing miserably to do so. My theory is that it's snapping every other time, because the previous lerp hasn't finished it's thing yet. I think if I wait long enough between camera moves, I'll reduce the chance of the camera snapping to it's end position the next time it's asked to move.
So I think the way to solve this would be to successfully break the lerp?
note: I'm using lerp because I like the 'ease in' and 'ease out' effect it has.
The reason your Lerp isn`t working is because your are only calling it once in each of your methods. you should either place lerp function in Update function or continually call your method in update until it is finished. Alternativley, and probably for the best.. you should place you Lerp function into a co-routine. I have posted a link to UnityGems (Gotchas) this site will help you resolve you problem easily.. look for co routines (both js/us & C#) Take care dude, and let me know if oyur problem persists, we will go through it step by step
Answer by robertbu · Mar 20, 2014 at 10:24 PM
My theory is that it's snapping every other time, because the previous lerp hasn't finished it's thing yet.
Your analysis is likely correct. Your using Lerp() this way is common in Unity, but it is a non-traditional use of a Lerp(). The final parameter you are passing (Time.deltaTime * camSpeed) evaluates to some small value. That means that each time Lerp() is called, you move some small fraction between the current position and the destination. The fraction remains approximately the same, but the distance shrinks. Thant means that the amount moved each frame shrinks.
The 'problem' with this kind of logic is that it can take a really long time to reach the destination. It kinda like the old adage, "how many days will it take me to each my goal if I cover half the distance to the goal each day?" Answer: never. If Unity's vector comparison was exact (it actually compares to see if the magnitude of the difference in positions is below some thereshold), and if we had infinite precision floating point calculations, your 'transform.position != targetPosition' would never go to false. One fix is to use a threshold rather than Unity's comparison:
while (Vector3.Distance(transform.position, targetPosition) > 0.05) {
This will dramatically reduce the time for the code to complete.
function MoveCam ()
{
targetPosition = Vector3 (11.5, 0, -5);
while (Vector3.Distance(transform.position, targetPosition) > 0.05)
{
transform.position = Vector3.Lerp (transform.position, targetPosition, Time.deltaTime * camSpeed);
yield;
if (Mathf.Abs(transform.position.x - targetPosition.x) < someThreshold)
{
print ("breaking right");
moveCamRight = false;
break;
}
}
}
Note the one other change I made:
if (Mathf.Abs(transform.position.x - targetPosition.x) < someThreshold)
You don't want to directly compare two floating point numbers (which was essentially what you were doing with the subtraction and comparison to zero). I doubt this line was ever firing. You'll have to figure out some appropriate value for 'someThreshold'.
All 3 of you we're very helpful. And you all have helped explain what I was doing wrong, thanks!
I'm goIng to go with robs suggestion as it should keep the ease in and out effect my using lerp() wrong has. Lol
If you want to have the ease in/out, then I suggest that ins$$anonymous$$d of using Lerp, you create an AnimationCurve with EaseInOut, and evaluate it's value using a variable between 0 and 1. I see a lot of people using Lerp this way, and while it is nice, it obfuscates its real meaning and sometimes causes confusion as why it is not working, as in your case.
Answer by suribe · Mar 20, 2014 at 10:15 PM
Lerp means Linear Interpolator, which means that it interpolates linearly between two values, using a third one to determine the exact interpolation point. So if you provide values A and B, and ask for it to interpolate at 0, it will provide A. At 1 it will provide B, at 0.5 the exact middle value, etc. But instead of providing a value between 0 and 1, you are giving it small values (Time.deltaTime * camSpeed is probably always something below 0) and interpolating between the result of the previous interpolation and the value B. This will provide a smooth interpolation which is not linear, and will (theoretically) never finish.
So lets suppose A = 0, B = 100, t = Time.deltaTime * camSpeed = 0.1
A = Lerp (A, B, t) = Lerp (0, 100, 0.1) = 10 A = Lerp (A, B, t) = Lerp (10, 100, 0.1) = 19 ... After a while, this will look like:
A B t
0 100 0,1
10 100 0,1
19 100 0,1
27,1 100 0,1
34,39 100 0,1
40,95 100 0,1
46,85 100 0,1
52,17 100 0,1
56,95 100 0,1
61,25 100 0,1
You see now why it never reaches the value you want? What you have to do is set a floating point variable such that it will go from 0 to 1, and interpolate from the initial camera position to the target one, using that value.
Something like:
t = 0;
targetPosition = Vector3 (0, 0, -5);
initialPosition = transform.position;
transform.position = Vector3.Lerp(initialPosition, targetPosition, t);
...
t += Time.deltaTime;
if (t >= 1) {
t = 1;
animating = false; // some way to know it finished...
}
Second thing: do this in the Update() method. Just set up a variable like this animating = false, and set it to yes at the start.
void Update()
{
if (animating) {
t += Time.deltaTime * camSpeed;
if (t >= 1) {
animating = false;
}
transform.position = Vector3.Lerp(initialPosition, targetPosition, t);
}
}
Your answer
Follow this Question
Related Questions
Make Lerp or other more fluid or continuous 3 Answers
How to lerp an object's scale? 2 Answers
Vector3.Lerp move weapon up to players face 2 Answers
Computation of Vector3.Lerp, does it check for change? 3 Answers
Using lerp to scale 1 Answer