Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice
  3. Join us on November 16th, 2023, between 1 pm and 9 pm CET for Ask the Experts Online on Discord and on Unity Discussions.
    Dismiss Notice

Scaling Object Using Lerp

Discussion in 'Scripting' started by SoftwareEngineer, Jun 15, 2016.

  1. SoftwareEngineer

    SoftwareEngineer

    Joined:
    Jan 4, 2014
    Posts:
    52
    transform.localScale = Vector3.Lerp(transform.localScale, transform.localScale * 2, Time.deltaTime * 10);
    This is the code I am using. However, when I press key to increase scale, scale of object is increased suddenly. Lerp does not work. Any idea?
     
  2. ericbegue

    ericbegue

    Joined:
    May 31, 2013
    Posts:
    1,353
    Lerp works. It just does not work as your want it to work.

    The Lerp function is often used (abused) with deltaTime as third parameter to achieve a damping effect. Thought that might yield a acceptable result, that's not how lerp is supposed to be used. The SmoothDamp (and its variants) function is more appropriate for this usage.
     
    sharkspread and jtsmith1287 like this.
  3. SoftwareEngineer

    SoftwareEngineer

    Joined:
    Jan 4, 2014
    Posts:
    52
    I understand what my problem is. I am using it in getkeydown and since it works for 1 frame my object is scaled instantly. How can I solve this problem?
     
  4. boolfone

    boolfone

    Joined:
    Oct 2, 2014
    Posts:
    289

    You may want to try something like this:

    Code (CSharp):
    1.     int scalingFramesLeft = 0;
    2.  
    3.  
    4.     // Use this for initialization
    5.     void Start ()
    6.     {
    7.    
    8.     }
    9.  
    10.     // Update is called once per frame
    11.     void Update ()
    12.     {
    13.  
    14.         if (Input.GetKeyDown (KeyCode.S)) {
    15.             scalingFramesLeft = 10;
    16.         }
    17.  
    18.  
    19.         if (scalingFramesLeft > 0) {
    20.             transform.localScale = Vector3.Lerp (transform.localScale, transform.localScale * 2, Time.deltaTime * 10);
    21.             scalingFramesLeft--;
    22.         }
    23.  
    24.  
    25.  
    26.     }
    I tried the code, and it does gradually scale the object over 10 frames.

     
    Last edited: Jun 16, 2016
    alline_mi and Azurne like this.
  5. SoftwareEngineer

    SoftwareEngineer

    Joined:
    Jan 4, 2014
    Posts:
    52
    Thank you very much. Saved my life :)
     
  6. Brathnann

    Brathnann

    Joined:
    Aug 12, 2014
    Posts:
    7,146
    Another suggestion is to consider a tween system. There are several free ones on the asset store that work really well and will also allow for other options. I have used itween and leanTween. There is also a dotween that I've heard is really good.

    Works great for things like this. Normally you can just pass in a start value, end value, and the time you want it to take to get from start to end.
     
    ericbegue likes this.
  7. ericbegue

    ericbegue

    Joined:
    May 31, 2013
    Posts:
    1,353
    Confirming DOTween is a great tweening system. The API is neat and yet allows you to customize the tweening exactly how you want it.
     
    Last edited: Jun 16, 2016
  8. listener

    listener

    Joined:
    Apr 2, 2012
    Posts:
    179
    Like ericbegue mentioned Lerp is often being misused :) it can work though if you as last parameter add Time.deltaTime * something you will get value with ease out effect as it comes closer to target the increments will become less and less but just so you know if you use it like this it will never reach target value because each iteration will increase for less and less basically indefinitely.

    If you wish to use Lerp as it is planned use last parameter as value from 0 to 1. 0 meaning start value 1 meaning end value and 0.5 meaning 50% bigger 1 meaning 100% bigger. And increment between 0 to 1 is left at your discretion.

    Also there is another problem with your code:

    Code (CSharp):
    1. transform.localScale = Vector3.Lerp(transform.localScale, transform.localScale * 2, Time.deltaTime * 10);
    you are lerping by using localScale as start position and localScale * 2 as target so each pass you increase local scale and then use it as target scale again times 2 so it is kinda like endless loop of scaling since you are scaling start and end scale at same time.

    I would suggest to cache your target scale so you scale toward independent vector value or at least have check to make sure that you reached the value you wish.
     
    SoftwareEngineer likes this.
  9. SoftwareEngineer

    SoftwareEngineer

    Joined:
    Jan 4, 2014
    Posts:
    52
    Thank you very much for your help but my problem was different. I was trying to use lerp inside the GetKeyDown and since it works for one frame my script does not work. Now I have a different question:

    if (scaleFrameLeft > 0)
    {
    scaleFrameLeft = 10;
    }

    if (scaleFrameLeft > 0)
    {
    o1.transform.localScale = Vector3.Lerp(o1.transform.localScale, o1.transform.localScale * 2, Time.deltaTime * 10);
    scaleFrameLeft--;
    }

    As you can see I have to check everyframe whether scaleFrameLeft is greater than 0 or not and this is not a good practice. I want to know if I can create an external object which will be created when I press F and do the job above and will be destroyed after done the job? I hope I am clear.
     
  10. listener

    listener

    Joined:
    Apr 2, 2012
    Posts:
    179
    I am not exactly sure what are you trying to achieve.

    But if you wish to spawn an object you can make prefab and use Instantiate() to create object that will have script attached and perform what you want.
     
  11. Fajlworks

    Fajlworks

    Joined:
    Sep 8, 2014
    Posts:
    344
    Take this extension method code and place it into your project:
    Code (CSharp):
    1. public static class LerpHelpExtensions
    2.     {
    3.         public static Coroutine LerpCoroutine(this GameObject gameObj, float time, System.Action<float> block, bool includeZero = false)
    4.         {
    5.             MonoBehaviour behaviour = gameObj.GetComponent<MonoBehaviour> ();
    6.             if ( behaviour == null )
    7.                 return null;
    8.            
    9.             return behaviour.LerpCoroutine (time, block, includeZero);
    10.         }
    11.        
    12.        
    13.         public static Coroutine LerpCoroutine(this MonoBehaviour behaviour, float time, System.Action<float> block, bool includeZero = false)
    14.         {
    15.             return behaviour.StartCoroutine (_LerpCoroutine (time, block, includeZero));
    16.         }
    17.        
    18.         static IEnumerator _LerpCoroutine(float time, System.Action<float> block, bool includeZero = false)
    19.         {
    20.             if ( time <= 0f )
    21.             {
    22.                 block(1f);
    23.                 yield break;
    24.             }
    25.            
    26.             float timer = 0f;
    27.             if ( includeZero )
    28.             {
    29.                 block(0f);
    30.                 yield return null;
    31.             }
    32.            
    33.             while ( timer < time )
    34.             {
    35.                 timer += Time.deltaTime;
    36.                 block(Mathf.Lerp(0f, 1f, timer/time));
    37.                 yield return null;
    38.             }
    39.         }
    40.        
    41.         public static Coroutine AnimateComponent<T>(this MonoBehaviour behaviour, float time, System.Action<T,float> block) where T : Component
    42.         {
    43.             if ( block == null )
    44.                 return null;
    45.            
    46.             T component = behaviour.GetComponent<T> ();
    47.             if ( component == null || !behaviour.gameObject.activeInHierarchy)
    48.                 return null;
    49.            
    50.             return behaviour.StartCoroutine (_LerpCoroutine(time, (timer)=>
    51.             {
    52.                 block(component, timer);
    53.             }));
    54.            
    55.         }
    56.     }
    Now, all you have to do to animate your component is:
    Code (CSharp):
    1. public class MyScript : MonoBehaviour
    2. {
    3.      void Start ()
    4.      {
    5.           float duration = 0.16f;
    6.           Vector3 startScale = transform.localScale;
    7.           Vector3 endScale = startScale * 2f;
    8.  
    9.           this.AnimateComponent<Transform> (duration, (t, time) =>
    10.           {
    11.                t.localScale = Vector3.Lerp (startScale, endScale, time);
    12.           });
    13.      }
    14.  
    15.      // you can even put it inside a coroutine
    16.      IEnumerator MyCoroutine()
    17.      {
    18.           float duration = 0.16f;
    19.           Vector3 startScale = transform.localScale;
    20.           Vector3 endScale = startScale * 2f;
    21.  
    22.           yield return this.AnimateComponent<Transform> (duration, (t, time) =>
    23.           {
    24.                t.localScale = Vector3.Lerp (startScale, endScale, time);
    25.           });
    26.  
    27.           Debug.Log ("finished");
    28.      }
    29. }
    Not only you can use this script to handle transform changes over time, but you can use it with any component, perhaps with uGUI components to change alpha value:
    Code (CSharp):
    1. void Start()
    2. {
    3.      this.AnimateComponent<CanvasGroup>(0.5f, AnimateCanvas);
    4. }
    5.  
    6. void AnimateCanvas(CanvasGroup group, float time)
    7. {
    8.      group.alpha = Mathf.Lerp(0f, 1f, time);
    9. }
    10.  
    11.  
    Hope this little script helps!
     
  12. ericbegue

    ericbegue

    Joined:
    May 31, 2013
    Posts:
    1,353
    Without the technical details, what's the goal you are trying to achieve?
    1. Scale the object to a target scale when the button is pressed.
    2. Scale the object as long as the button is down.
    3. Something else.
     
  13. jaredKreate

    jaredKreate

    Joined:
    Sep 26, 2015
    Posts:
    1
    Hey, we actually created a video to cover this type of functionality that I will link to here:

    This video covers lerp of scale over time so hopefully it helps. We used IEnumerators to actually complete the scale updates, which helps to make the lerp a little smoother.
     
    RoadSpell and Surd23 like this.
  14. Akhrorjon

    Akhrorjon

    Joined:
    Dec 24, 2019
    Posts:
    3
    May be my code can also help someone:
    Scaling object over time
    Code (CSharp):
    1. private void Start() {
    2.   var scaleTo = new Vector(1.5f, 1.5f, 1.5f);
    3.    StartCoroutine(ScaleOverSeconds(objectToScale, scaleTo, 1.0f);
    4. }
    5.  
    6. public  IEnumerator ScaleOverSeconds(GameObject objectToScale, Vector3 scaleTo, float seconds)
    7.         {
    8.             float elapsedTime = 0;
    9.             Vector3 startingScale = objectToScale.transform.localScale;
    10.             while (elapsedTime < seconds)
    11.             {
    12.                 objectToScale.transform.localScale = Vector3.Lerp(startingScale, scaleTo, (elapsedTime / seconds));
    13.                 elapsedTime += Time.deltaTime;
    14.                 yield return new WaitForEndOfFrame();
    15.             }
    16.             objectToScale.transform.position = scaleTo;
    17.         }
     
    abhijeetsridhar likes this.
  15. Nickjd331

    Nickjd331

    Joined:
    Aug 22, 2014
    Posts:
    29
    Just need to change the last line to: objectToScale.transform.localScale = scaleTo; and then works nicely.