Why GameObject jumping from position when using LERP rather than moving smoothly?

I am trying to move a gameObject from one position to other using LERP function after playing an animation.In order to move the GameObject we need to disable the animator.After that I am calling a Coroutine to use LERP function but the GameObject is jumping from one position to another.What to do to slowly move GameObject from one position to other.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.XR.ARFoundation;
public class ImageTrackingSess : MonoBehaviour
{
    ARTrackedImageManager ImgTrackedmanager;
    public GameObject Showprefabs;
    public Camera Arcam;
    public float speed = 5f;
    public float distance = 4;
    public float rotationspeed = 100f;
    private Animator animmove;
    bool frontcam = false;
    GameObject go;
    Vector3 randompos;
    Quaternion Lookrot;
    public float smoothFactor = 0.1f;
    public GameObject Glassbreak;
    public AudioSource audioSource;
    void Awake()
    {
        ImgTrackedmanager = GetComponent<ARTrackedImageManager>();
    }
    // Start is called before the first frame update
    void Start()
    {
        randompos = new Vector3(Random.Range(-20.0f, 20.0f), 0, Random.Range(3.0f, 20.0f));
     
    
    }
    // Update is called once per frame
    void Update()
    {
    
        if (frontcam == true)
        {
        
            animmove = Showprefabs.transform.GetChild(0).GetComponent<Animator>();
            var aa = animmove.GetCurrentAnimatorStateInfo(1).IsName("Move");
            bool val = animmove.GetBool("Movement");
      
            animmove.SetBool("Movement", true);
            speed = 10f;
            float step = speed * Time.deltaTime;
        
            if (animmove.GetCurrentAnimatorStateInfo(1).normalizedTime > 1)
            {
                               animmove.SetBool("Movement", false);
                if (animmove.GetCurrentAnimatorStateInfo(1).IsName("Bite"))
                {
                
                    Showprefabs.transform.GetChild(0).GetComponent<Animator>().enabled = false;
                    
                    StartCoroutine(MoveTowardsScreen());
                    frontcam = false;
                    Debug.Log("Still Playing.." );
                }
            }
  
      
        }
  
    }
    IEnumerator MoveTowardsScreen()
    {
        speed = 1f;
        float step = speed * Time.deltaTime;
    
        var targetObject = Showprefabs.transform.GetChild(0);
        var currentPosition = targetObject.position;
        var targetPosition = Camera.main.transform.position
                                   // Place it 60cm in front of the camera
                                   + Arcam.transform.forward * 2f
        // additionally move it up 20cm
        + Arcam.transform.up * 1f;
        targetObject.position = Vector3.MoveTowards(currentPosition, targetPosition, step * Time.deltaTime);
        //targetObject.position = Vector3.Lerp(currentPosition, targetPosition, smoothFactor);
        Glassbreak.SetActive(true);
        //Showprefabs.transform.GetChild(0).GetComponent<Animator>().enabled = true;
        audioSource.Play();
        yield return null;
        //yield return new WaitForSeconds(5f);
    }
  
  
    void OnEnable()
    {
        if(frontcam==false)
        ImgTrackedmanager.trackedImagesChanged += OnTrackedImagesChanged;
    }
    void OnDisable()
    {
        ImgTrackedmanager.trackedImagesChanged -= OnTrackedImagesChanged;
    }
    public void MakeContentAppearAt(Transform content, Vector3 position)
    {
        MakeContentAppearAt(content, position);
    }
    void OnTrackedImagesChanged(ARTrackedImagesChangedEventArgs eventArgs)
    {
        if (frontcam == false)
        {
          foreach (var trackedImage in eventArgs.added)
          {
            // Give the initial image a reasonable default scale
            //trackedImage.transform.localScale = new Vector3(0.01f, 1f, 0.01f);
        
                if (trackedImage.referenceImage.name == "Img1")
                {
                    GameObject obj1 = Instantiate(Showprefabs,Vector3.zero,Quaternion.identity);
                    Showprefabs = obj1;
                    Showprefabs.transform.position = new Vector3(trackedImage.transform.position.x,-1f,trackedImage.transform.position.z);
                    Showprefabs.transform.rotation = trackedImage.transform.rotation;
                    Showprefabs.transform.parent = null;
                 
                  
                
                    Debug.Log("Before Coroutine");
                     StartCoroutine(Frontofcam());
                }
            }
        }
        foreach (var trackedImage in eventArgs.updated)
        {
        
        }
        
    }
    IEnumerator Frontofcam()
    {
        Debug.Log("Front of cam");
        yield return null;
    
        frontcam = true;
    }
}

It would be wise to re-read the description of Lerp. The third parameter tells lerp how far between A and B to interpolate. If it’s Zero, it’ll be A’s Position, if it’s one, it’ll be B’s Position, and and value between 0 and 1 is (in percent) how far between them. This means that you should change the third paramter (smoothFactor) each pass through your coroutine so that it slowly grows from 0 to 1. Your code, it seems, keeps it fixed at 0.1f. Since you are then storing the new Position into the object, and read it on the next pass (that never comes – see below), you are technically Lerping, but using Lerp this way is nonstandard and difficult to understand (some people use it because using it this way can give slow-down effects towards the end, but there are much better functions available for that: see here).

Furthermore, your coroutine seems to lack a loop. It will only execute once, so there is no feed for it to be a coroutine. Finally, you never actually invoke MoveTowardsScreen(), so maybe it’s no surprise there’s no Lerping going on at all.

I deleted the StartCoroutine statement while editing.Instead of Lerp I used move towards with speed but the GameObject is stuck at the same position that means it is not updating.I thought only after executing Coroutines the next line in the code will get executed.It make the condition false even before the coroutine gets finished.

Please show us the code that is not working in it’s entirety - if you edit it, there is a good chance that you edit out the buggy part. When you name a thread something containing ‘LERP’ (in caps), expect readers to first look for that.

Coroutines will not halt the code at all, they execute at the end of the frame and execution of the main method that calls the coroutine resumes immediately.

May 08 5:21 PM - Codeshare This is the full code.The MoveTowardsScreen() coroutine I am calling.The GameObject is jumping rather than slowly moving.I used LERP(Jumps towards the position) and Vector3.MoveTowards(the gameobject stops after the animation).How to complete Coroutine and call frontcam = false;

Unfortunately, I can’t access codeshare. Perhaps consinder posting the code here.

Updated the code.

As you coded, your character moves 0.1 * distance from the character to taget point every frame, 60 times per second. If it is 10 meter away from camera, it will jump 1m first frame, 0,9m second, 0,81m third frame and so on. If running 60 fps, one frame is 0,016 second. It will go about 25% of remaining distance in first 3 frames of movement. No wonder it looks almost like instant teleport.
It looks like you do not understand this. Here’s material what will help you dive into lerping things How to Lerp like a pro | Chico Unity3D

What abt movetowards in the code?How to apply that?The statement getting false makes it only run once.

You need to loop the routine like this

do {
  MoveOneStepToTarget();
  yield return null;
} while(target is far away) ;

Tried the code below but same effect

  Transform targetGo;
  Vector3 currentPos;
  Vector3 targetPos;



 targetGo = Showprefabs.transform.GetChild(0);
 currentPos = targetGo.position;
 targetPos = Camera.main.transform.position;


do
 {
   StartCoroutine(MoveTowardsScreen());
 } while (currentPos==targetPos);

   frontcam = false;

 IEnumerator MoveTowardsScreen()
    {
        Debug.Log("Still Playing..");
        speed = 1f;
        float step = speed * Time.deltaTime;

     

        var targetPosition = Camera.main.transform.position
                                   // Place it 60cm in front of the camera
                                   + Arcam.transform.forward * 2f
        // additionally move it up 20cm
        + Arcam.transform.up * 1f;
        targetGo.position = Vector3.MoveTowards(currentPos, targetPosition, step * Time.deltaTime);

        //targetObject.position = Vector3.Lerp(currentPosition, targetPosition, smoothFactor);
        Glassbreak.SetActive(true);
        audioSource.Play();
        //Showprefabs.transform.GetChild(0).GetComponent<Animator>().enabled = true;

        yield return null;
        //yield return new WaitForSeconds(3f);




    }


 IEnumerator MoveTowardsScreen()
    {
        Debug.Log("Still Playing..");
        speed = 1f;
        float step = speed * Time.deltaTime;

    

        var targetPosition = Camera.main.transform.position
                                   // Place it 60cm in front of the camera
                                   + Arcam.transform.forward * 2f
        // additionally move it up 20cm
        + Arcam.transform.up * 1f;
        targetGo.position = Vector3.MoveTowards(currentPos, targetPosition, step * Time.deltaTime);

        //targetObject.position = Vector3.Lerp(currentPosition, targetPosition, smoothFactor);
        Glassbreak.SetActive(true);
        audioSource.Play();
        //Showprefabs.transform.GetChild(0).GetComponent<Animator>().enabled = true;

        yield return null;
        //yield return new WaitForSeconds(3f);




    }

Wrong place. You need to loop routine body, not it’s start call. 1st and 3rd examples here Unity - Scripting API: MonoBehaviour.StartCoroutine

https://learn.unity.com/ here are some good tutorials I suggest you complete before continuing your development.

void Update()
    {
       
        if (frontcam == true)
        {
           
            animmove = Showprefabs.transform.GetChild(0).GetComponent<Animator>();
            
            animmove.SetBool("Movement", true);

      
            speed = 10f;
            float step = speed * Time.deltaTime;

         

            if (animmove.GetCurrentAnimatorStateInfo(1).normalizedTime > 1)
            {
             
                animmove.SetBool("Movement", false);
                if (animmove.GetCurrentAnimatorStateInfo(1).IsName("Bite"))
                {
                  
                    Showprefabs.transform.GetChild(0).GetComponent<Animator>().enabled = false;
                  
                    targetGo = Showprefabs.transform.GetChild(0);
                    currentPos = targetGo.position;
                 
                    var targetPosition = Camera.main.transform.position
                                               // Place it 60cm in front of the camera
                                               + Arcam.transform.forward *7f
                    // additionally move it up 20cm
                    + Arcam.transform.up * 3f;
                    targetPos = targetPosition;

                    targetGo.position = Vector3.MoveTowards(currentPos, targetPos, step);
                  
                    
                    if((currentPos-targetGo.position).sqrMagnitude<=minDistance*minDistance)
                    {
                        Debug.Log("Same Same");
                        Glassbreak.SetActive(true);
                        audioSource.Play();
                        frontcam = false;
                    }

                }

            }
     
         
        }

     
    }
private void Update() {
  if(charater needs to walk somewhere) {
    StartCoroutine(WalkRoutine());
  }
}

private IEnumerator WalkRoutine() {
  do {
    MoveOneStepToTarget();
    yield return null;
  } while(target is far away) ;
}
1 Like

The above code I pasted works okay…Need to adjust Arcam.transform.forward *7f(change float value ) to come in front of camera.

You may easily ajust it runtime, just move it to inspector fields

[Range(0,100)] public float transformForwardFactor = .7f;
Arcam.transform.forward * transformForwardFactor

But it is AR,How can I adjust with inspector fields?I am testing on phone.

1 Like

I read this forum a while back.Looking at the posts no one got it working. Anyway will try it tomorrow