0

I've got some simple code here. The issue I am having is that the images contract to the center (local position Vector3.zero) at what seems to be nearly double the speed as they move away from the center. I believe I am using them same logic to move them so I was wondering if anyone could tell me what could cause such behavior.

Any advice on making the code itself better is also welcome but my main concern is the speed of the interpolation. I probably should have passed the current time via parameter instead of the total time but you know... I do not make perfect decisions the first time every time.

The specific lines in questions:

IEnumerator ContractImages(float totalTime)
{
    yield return m_WaitForEndOfFrame;

    m_CurrentContractionTime += Time.deltaTime;

    float t =  m_CurrentContractionTime / totalTime;

    Debug.Log(string.Format("Expansion Rate Factor: {0}", t));
    Debug.Log(string.Format("Current Expansion Time: {0}", m_CurrentContractionTime));

    for (int i = 0; i < m_MovingImages.Length; i++)
    {
        var r = m_MovingImages[i].GetComponent<RectTransform>(); //Optimize

        r.localPosition = Vector3.Lerp(r.localPosition, Vector3.zero, t);
    }

    if (m_CurrentContractionTime < totalTime)
        m_ContractionRoutine = StartCoroutine(ContractImages(totalTime));

    else if (m_ContractionRoutine != null)
    {
        StopCoroutine(m_ContractionRoutine);
        InvokeContractionComplete();
        m_CurrentContractionTime = 0;
    }
}

IEnumerator ExpandImages(float totalTime)
{
    yield return m_WaitForEndOfFrame;

    m_CurrentExpansionTime += Time.deltaTime;

    float t = m_CurrentExpansionTime / totalTime;

    Debug.Log(string.Format("Expansion Rate Factor: {0}", t));
    Debug.Log(string.Format("Current Expansion Time: {0}", m_CurrentExpansionTime));

    for (int i = 0; i < m_MovingImages.Length; i++)
    {
        var r = m_MovingImages[i].GetComponent<RectTransform>(); //Optimize

        r.localPosition = Vector3.Lerp(Vector3.zero, m_StartingVectors[i], t);
    }

    if (m_CurrentExpansionTime < totalTime)
        m_ContractionRoutine = StartCoroutine(ExpandImages(totalTime));

    else if (m_ContractionRoutine != null)
    {
        StopCoroutine(m_ExpansionRoutine);
        InvokeExpansionComplete();

        Debug.Log("Expansion Complete: " + totalTime / m_CurrentExpansionTime);
        m_CurrentExpansionTime = 0;
    }
}
Relu
  • 37
  • 5
  • 1
    Why do your functions start another coroutine with the same function inside of them? How many of the same routine do you have running at the same time? – Retired Ninja Aug 07 '20 at 19:31
  • With recursive coroutine structures like this there is usually two actual routines in use - the one being started and the one being finished. For example the code after StopCoroutine still executes before terminated the routine. Edit: You can confirm with the profiler. – Relu Aug 07 '20 at 19:39

1 Answers1

1

Well the first difference that seems obvious is that in ContractImages, you lerp from the current position, which grows ever closer to the destination, and in ExpandImages, you lerp from a constant position. So of course the ContractImages lerp will progress faster in the middle of the lerp.

For instance, assuming the expand position is new Vector3(1f,0f,0f) and totalTime is 1f, and Time.deltaTime is 0.1f:

First frame

Contract

r.localPosition = Vector3.Lerp(new Vector3(1f,0f,0f), Vector3.zero, 0.1f); 
             // = new Vector3(0.9f, 0f, 0f); 
             // dist = 0.1f

Expand

r.localPosition = Vector3.Lerp(Vector3.zero, new Vector3(1f,0f,0f), 0.1f);
             // = new Vector3(0.1f, 0f, 0f);
             // dist = 0.1f

Second frame

Contract

r.localPosition = Vector3.Lerp(new Vector3(0.9f,0f,0f), Vector3.zero, 0.2f); 
             // = new Vector3(0.78f, 0f, 0f);
             // dist = 0.22f

Expand

r.localPosition = Vector3.Lerp(Vector3.zero, new Vector3(1f,0f,0f), 0.2f);
             // = new Vector3(0.2f, 0f, 0f);
             // dist = 0.2f

Third frame

Contract

r.localPosition = Vector3.Lerp(new Vector3(0.78f,0f,0f), Vector3.zero, 0.3f); 
             // = new Vector3(0.546f, 0f, 0f);
             // dist = 0.454f

Expand

r.localPosition = Vector3.Lerp(Vector3.zero, new Vector3(1f,0f,0f), 0.3f);
             // = new Vector3(0.3f, 0f, 0f);
             // dist = 0.3f

Basically, you should consider lerping between constants in both cases:

IEnumerator ContractImages(float totalTime)
{
    yield return m_WaitForEndOfFrame;

    m_CurrentContractionTime += Time.deltaTime;

    float t =  m_CurrentContractionTime / totalTime;

    Debug.Log(string.Format("Expansion Rate Factor: {0}", t));
    Debug.Log(string.Format("Current Expansion Time: {0}", m_CurrentContractionTime));

    for (int i = 0; i < m_MovingImages.Length; i++)
    {
        var r = m_MovingImages[i].GetComponent<RectTransform>(); //Optimize

        r.localPosition = Vector3.Lerp(m_StartingVectors[i], Vector3.zero, t);
    }

    if (m_CurrentContractionTime < totalTime)
        m_ContractionRoutine = StartCoroutine(ContractImages(totalTime));

    else if (m_ContractionRoutine != null)
    {
        StopCoroutine(m_ContractionRoutine);
        InvokeContractionComplete();
        m_CurrentContractionTime = 0;
    }
}
Ruzihm
  • 19,749
  • 5
  • 36
  • 48
  • Yup. Should have spotted that. Good call. Even if the new keyword is to be abhored! :P Much Thanks, sire. – Relu Aug 07 '20 at 20:00