0
\$\begingroup\$
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class NaviManager : MonoBehaviour
{
    public enum TransitionState
    {
        None,
        MovingTowards,
        Transferring
    }

    public Transform player;
    public Transform carte;
    public Animation anim;
    public Transform destinationTransform;
    public float speed;
    public float distanceToStop;
    public float lerpTime;
    public UnlockCrate unlockCarte;

    private GameObject rig_f_middle;
    private Transform originTransform;
    private Vector3 originalScale;
    private float timer;
    private bool openonce = false;
    private TransitionState state = TransitionState.MovingTowards;
    private bool isScaling = false;

    void Start()
    {
        originalScale = transform.localScale;

        rig_f_middle = GameObject.Find("rig_f_middle.02.R");
    }

    void Update()
    {
        var dist = Vector3.Distance(carte.position, player.position);


        if (dist < 1.5f)
        {
            transform.localScale = Vector3.Lerp(transform.localScale, new Vector3(0.001f, 0.001f, 0.001f), Time.deltaTime * 1f);

            if (openonce == false)
            {
                anim.Play("Crate_Open");
                openonce = true;
            }

            switch (state)
            {
                case TransitionState.MovingTowards:
                    var v = rig_f_middle.transform.position - transform.position;
                    if (v.magnitude < 0.001f)
                    {
                        state = TransitionState.Transferring;
                        originTransform = rig_f_middle.transform;
                        timer = 0;
                        return;
                    }
                    Vector3 moveDir = v.normalized;
                    transform.position += moveDir * speed * Time.deltaTime;
                    break;

                case TransitionState.Transferring:
                    timer += Time.deltaTime;
                    this.transform.position = Vector3.Lerp(originTransform.position, destinationTransform.position, timer);
                    if (timer >= 1.0f)
                    {
                        this.transform.parent = destinationTransform;
                        state = TransitionState.None;
                        this.enabled = false;
                        return;
                    }
                    break;

                default:
                    this.enabled = false;
                    return;
            }
        }
    }
}

what I need to do is to scale the transform while it's moving to another object and become a child of that object. and I want that while the transform is started moving than to start smoothly slowly also to scale it down and when the object is reaching to its target the scaling also should be reaching the target 0.001

The problems I'm facing :

  1. The scaling is never reaching 0.001f but close to it.

  2. If I'm using coroutine for the scaling then it will not be smoothly flowing, the transform will wait in the end for the coroutine to end before it will be a child that is why I'm doing the scaling in the Update and not in a coroutine.

  3. How can I make in the Update the scaling without coroutine that it will scale the time the transform is moving I mean that it will not scale too fast to 0.001 and too slow but will scale while it's moving?

\$\endgroup\$
3
  • \$\begingroup\$ Does this answer your question? Best way to interpolate player movements in a very fast paced Unity game?. Don't be alarmed by the different question title as the answer there seems to cover your issue with lerping. \$\endgroup\$
    – user35344
    Jul 5, 2021 at 7:23
  • 1
    \$\begingroup\$ If I understand your question correctly, then you want an object to move from start to destination, and simultaneously linearly interpolate its scale from the original scale to 1/1000th as it progresses from start to destination. Is that correct? \$\endgroup\$
    – Philipp
    Jul 5, 2021 at 10:10
  • \$\begingroup\$ @Philipp correct. \$\endgroup\$
    – Daniel Lip
    Jul 5, 2021 at 11:13

1 Answer 1

1
\$\begingroup\$

If I understand your question correctly, then you want an object to move from A to B, and simultaneously interpolate its scale from the original scale to 1/1000th as it progresses on that move.

I would approach this problem as follows:

  1. Calculate the current progression factor of the movement in form of a float between 0.0f (at the start) and 1.0f (at the end).
  2. Use that value as the linear interpolation factor for the Lerp methods on both the scale and the position.

So first, how do we calculate the progression?

We simply track the time which has passed, and divide it by the time we want the animation to take in full:

public class ScaleMove : MonoBehaviour {
    
    public float duration = 2.9f; // time in seconds we want the action to take
    
    private float durationCompleted = 0.0f; // time completed

    void Update() {
         durationCompleted += Time.deltaTime;             
         float progressionFactor = durationCompleted / duration;

    }

}

OK, now what we calculated this "progression factor" between 0 and 1, what do we do with it?

First we want to clamp it to an area between 0 and 1, so it doesn't get beyond 1.0f when the duration is over. And then we use it for the linear inerpolation of both size and position:

 progressionFactor = Mathf.Clamp01(progressionFactor);
 transform.position = Vector3.Lerp(startPosition, endPosition, progressionFactor);
 transform.scale = Vector3.Lerp(startScale, endScale, progressionFactor);

OK, but where do these start and end variables come from? And no, you can not take the start values from the transform of the object (at least not in Update) because those values change during the process (although you could substitute the end position by a reference to another Transform - that way the destination can move during the process and the script will adapt to that). I would recommend to make those private variables as well and set them by a public method which can be called by other scripts to initialize the movement action. That method (let's call it Go) could also takes care of managing whether or not the movement action is currently active. So it can be called again to repeat the action. The whole script would look something like this (untested code!):

public class ScaleMove : MonoBehaviour {
    
    public float duration = 1.0f; // time in seconds we want the action to take
    
    private float durationCompleted = 0.0f; // time completed
    private bool running = false;
    private Vector3 startPosition;
    private Vector3 endPosition; 
    private Vector3 startScale;
    private Vector3 endScale;

    public void Go(Vector3 startPosition, Vector3 endPosition, float startScale, float endScale) {
         this.startPosition = startPosition;
         this.endPosition = endPosition;
         this.startScale = new Vector3(startScale, startScale, startScale);
         this.endScale = new Vector3(endcale, endScale, endScale);
         running = true;
         durationCompleted = 0f;
    }

    void Update() {
         if (running) {
             durationCompleted += Time.deltaTime;             
             float progressionFactor = Mathf.Clamp01(durationCompleted / duration);
             transform.position = Vector3.Lerp(startPosition, endPosition, progressionFactor);
             transform.scale = Vector3.Lerp(startScale, endScale, progressionFactor);
             if (progressionFactor == 1.0f) {
                  running = false;
             }
         }
    }

}

"OK, it works, but it looks too linear for my taste. Can I add some easing to make it smoother?".

Sure, you can. A Unity beginner would now experiment with all kinds of math and weird abuse of Lerp in ways it's not supposed to be used to smooth the movement. Or perhaps bother with a 3rd party tweening library like DOTween.

But an experienced Unity developer will just add a public AnimationCurve variable to the script. This adds a handy curve-based editor to the inspector, allowing you to visually edit your time-to-progression function. You can then sample your animation curve with Evaluate(progressionFactor);

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .