FrakyDale
FrakyDale

Reputation: 727

Remove delay between lerps

I made a simple script that goes to one waypoint and then to the next.

My problem is that it seems to be a delay while going from waypoint1 to waypoint2 and i don't know why: enter image description here

¿Why is that delay happening and how can i remove it?

using UnityEngine;
using System.Collections;

public class Missile : MonoBehaviour
{
 public Vector3 finalTarget;
 public Transform forwardObject;

 public GameObject impactAreaPrefab;

 float smoothingDelay = 0.1f;
 bool fired = false;
 bool powerPhase = true;
 Vector3 currentTarget;

 private void OnEnable() {
     fire(new Vector3(-25.29f, 0.5f, -10.638f));
 }

 void fire(Vector3 coords) {
     currentTarget = forwardObject.position;
     finalTarget = coords;
     Instantiate(impactAreaPrefab, finalTarget, Quaternion.identity);
     fired = true;
 }

 void Update() {
     if (!fired) {
         return;
     }

     if (powerPhase && transform.position == currentTarget) {
         powerPhase = false;
         currentTarget = finalTarget;
         smoothingDelay = 0.05f;
     }

     transform.position = Vector3.Lerp(transform.position, currentTarget, Time.deltaTime / smoothingDelay);
     transform.rotation = Quaternion.Lerp(transform.rotation, Quaternion.LookRotation(Vector3.RotateTowards(transform.forward, currentTarget, 1, 0.0f)), Time.deltaTime / smoothingDelay);
 }
 }

Upvotes: 0

Views: 444

Answers (3)

user9211718
user9211718

Reputation:

So First thing read these post to get better understanding of Lerp function- https://chicounity3d.wordpress.com/2014/05/23/how-to-lerp-like-a-pro/ http://www.kinematicsoup.com/news/2016/8/9/rrypp5tkubynjwxhxjzd42s3o034o8

You should have a better understanding of lerp now. In summary lerp does a really simple thing. Say u have two values X and Y. For this example let us give them some value, X = 0, Y = 1, Now you want to get a value some percent between them, like u want to get a value which is 50% from X and Y. You can guess the answer is 0.5. The lerp equation for this would be

Mathf.Lerp(0, 1, 0.5f);

So simply- given two values, x and y, Mathf.Lerp returns a value that is t percent between them.

Now to properly use Lerp you need to cache the position before starting the lerp. Most times I use a coroutine to get this effect works pretty well and then u can use animation curve to change the third parameter to create some crazy good effects. For example on using a animation curve just comment i will write it.

For this problem of yours you have two options-

1) Lerp like a pro using Animation curve to manipulate the speed. Remember u can create animation curves in runtime too.

IENumerator Move(Transform toMove, Vector3 end, float duration){
    Vector3 startPos = toMove.position;
    float elapsed = 0f;
    while(elapsed < duration){
        elapsed += Time.deltaTime;
        toMove.position = Vector3.Lerp(startPos, end, elapsed / duration);//manipulate the last parameter to move the object linearly
        yield return null;//basically wait for next frame
    }
    toMove.position = end;//after lerp ends
}

Now you can instead of duration use speed and then with it you calculate the time required and change the speed to make it faster

float distance = Vector3.Distance(startPos, end);
toMove.position = Vector3.Lerp(startPos, end, elapsed / (distance/(speed * multiplier)));

2) Use Vector3.MoveTowards - This function moves a point to a end point with a given maximum step, requires three paramters, (currentPosition, end, step), u can multiply step with variable to control the speed, both work really good. Using this is much easier in most cases Example-

float step = speed * Time.deltaTime;//to make it framerate independent
transform.position = Vector3.MoveTowards(transform.position, end, step * multiplier);

Hope this helps. I am sorry I was unable to format my answer properly, hopefully will get better at answering. Any edits to improve the answer are welcomed :)

Upvotes: 1

Horothenic
Horothenic

Reputation: 678

I recommend using iTween for smooth movement.

I modified iTween at some point for me to be able to do anything I want. like this:

    public static void Rotate (Transform transform, Vector3 target, float transitionTime, Action onEnd = null, bool ignoreTimescale = false, iTween.EaseType ease = iTween.EaseType.easeInOutQuad, float delay = 0)
    {
        Vector3 from, to;

        from = transform.localEulerAngles;
        to = target;

        Action <object> onUpdateAction = (rotation => 
        {
            transform.localEulerAngles = (Vector3) rotation;
        });

        Action <object> onCompleteAction = (data => 
        {
            if (onEnd != null)
                onEnd ();
        });

        Hashtable hash = new Hashtable ();
        hash.Add ("from", from);
        hash.Add ("to", to);
        hash.Add ("time", transitionTime);
        hash.Add ("delay", delay);
        hash.Add ("easetype", iTween.EaseType.easeInOutQuad);
        hash.Add ("ignoretimescale", ignoreTimescale);
        hash.Add ("onupdate", onUpdateAction);
        hash.Add ("oncomplete", onCompleteAction);

        iTween.ValueTo (transform.gameObject, hash);
    }

That gives me full control in a variety of scenarios.

Here is the code if you want to implement it.

https://drive.google.com/open?id=1nLEEYTp-q4Kfh2n3nWQJcMXmPNtVPLLP

Upvotes: 0

Smith
Smith

Reputation: 461

That's happening, because you're using lerp not exactly properly. If you want to get linear movement you should cache your first argument (position/rotation on beginning) and provide increasing third parameter. This delay is happening because if your bullet is very close to final position and it's still trying to get there, but your current distance |finalPos - transform.position| is so small that your step Time.deltaTime/smoothingDelay is almost not moving it.

Vector3 startPos;
Vector3 finalPos;
float currentT = 0.0f;

void Update()
{
    currentT += Time.deltaTime;
    transform.position = Vector3.Lerp(startPos, finalPos, currentT);
}

Checking if Vector3 == Vector3 is also not a good idea. Use pattern from above and check if currentT is larger or equal to 1. If it's true then you're on final position. You get also some control over movement duration by dividing currentT.

Upvotes: 2

Related Questions