How to change an object movement direction in the middle using coroutine?

I’m using this script and i have multiple objects and when i change the slider value if the value getting higher the first button start moving up next time i change the slider value to higher value the next object start moving up and so on. the problem is when i change the slider value back down then i want the current moving object to start moving back down even if he still moving up. i want it to change direction in the middle smoothly and move down. and if i change the slider value to be more less then the next object should start moving down no matter if the last one still moving down. this is the logic. the up direction working fine but the down direction not working good. when i change the slider value down the objects still need to finish moving up and only then start moving down. and i want them to start moving down in the middle. the main goal is to change the directions in the middle.

i can’t figure out what is wrong.

using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using UnityEngine.UI;

public class ButtonsAmount : MonoBehaviour
{
    public Slider amountSlider;
    private List<GameObject> buttons = new List<GameObject>();
    public float animationDuration = 1.0f; // Duration for the animation

    private int currentButtonCount;
    private List<Coroutine> activeCoroutines = new List<Coroutine>();

    void Start()
    {
        currentButtonCount = Mathf.RoundToInt(amountSlider.value);
        amountSlider.onValueChanged.AddListener(delegate { OnSliderValueChanged(); });
        buttons = GameObject.FindGameObjectsWithTag("Button").ToList();
    }

    void OnSliderValueChanged()
    {
        int newButtonCount = Mathf.RoundToInt(amountSlider.value);
        if (newButtonCount != currentButtonCount)
        {
            if (newButtonCount > currentButtonCount)
            {
                MoveButtons(true); // Raise buttons
            }
            else
            {
                MoveButtons(false); // Lower buttons
            }
            currentButtonCount = newButtonCount;
        }
    }

    public void MoveButtons(bool raise)
    {
        StopAllActiveCoroutines(); // Stop all active coroutines before starting new ones
        StartCoroutine(MoveButtonsCoroutine(raise));
    }

    private void StopAllActiveCoroutines()
    {
        foreach (var coroutine in activeCoroutines)
        {
            StopCoroutine(coroutine);
        }
        activeCoroutines.Clear();
    }

    private IEnumerator MoveButtonsCoroutine(bool raise)
    {
        int buttonsToMove = (int)amountSlider.value;
        for (int i = 0; i < buttonsToMove; i++)
        {
            Vector3 startPosition = buttons[i].transform.position;
            Vector3 endPosition = new Vector3(startPosition.x, startPosition.y + (raise ? 100 : -100), startPosition.z); // Adjust the Y value as needed
            Coroutine moveCoroutine = StartCoroutine(MoveButton(buttons[i], startPosition, endPosition));
            activeCoroutines.Add(moveCoroutine);
        }
        yield return null;
    }

    private IEnumerator MoveButton(GameObject button, Vector3 startPosition, Vector3 endPosition)
    {
        float elapsedTime = 0;
        while (elapsedTime < animationDuration)
        {
            button.transform.position = Vector3.Lerp(startPosition, endPosition, (elapsedTime / animationDuration));
            elapsedTime += Time.deltaTime;
            yield return null;
        }
        button.transform.position = endPosition;
    }
}
type or paste code here

The answer is to not use a coroutine. This is just something that should be done in a per-frame basis in Update.

Coroutines are for fire-and-forget situations. If you would need to pause, resume, redirect, etc, then you don’t use a coroutine.

1 Like

^ ^ Exactly this… This pattern works every time:

Smoothing movement between any two particular values:

You have currentQuantity and desiredQuantity.

  • only set desiredQuantity
  • the code always moves currentQuantity towards desiredQuantity
  • read currentQuantity for the smoothed value

Works for floats, Vectors, Colors, Quaternions, anything continuous or lerp-able.

The code: SmoothMovement.cs · GitHub

1 Like