0

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);
 }
 }
FrakyDale
  • 647
  • 8
  • 22

3 Answers3

2

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.

Smith
  • 319
  • 2
  • 12
  • And if i want to increase the lerp speed, i should add a multiplier on the third param? – FrakyDale Dec 25 '18 at 10:44
  • Indeed, but remember that if distance between finalPos and startPos will vary your speed depend on this distance. So independently if your distance is 1 meter or 10 meters it will travel this distance in the same time. If you don't want this you should provide speed variable and divide your T by (distance / speed). – Smith Dec 25 '18 at 12:39
  • So it would be: Vector3.Lerp(startPos, finalPos, currentT / ( Vector3.Distance(startPos, finalPos) / speed)); ? – FrakyDale Dec 25 '18 at 14:02
  • Yup, something like that. Notice that you don't need to calculate distance in every frame, but just one time per travel. – Smith Dec 25 '18 at 17:45
  • Sorry to keep bothering about it but adding the speed formula brings me back to the initial problem: https://imgur.com/a/nqQ5pbc – FrakyDale Dec 25 '18 at 19:35
  • I'm not sure if it's that, but what you definetely should do is move your divide to currentT += Time.deltaTime / ( Vector3.Distance(startPos, finalPos) / speed). – Smith Dec 25 '18 at 21:10
  • That made it! So 100% confirmed i have to learn how Lerp works as i failed to correctly set 2 out of it's 3 parameters. Thanks!! – FrakyDale Dec 25 '18 at 22:21
1

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 :)

0

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

Horothenic
  • 680
  • 6
  • 12