unity-game-enginecoroutineienumerator

How to use Unity StopCoroutine when the Coroutine relies on mulitple conditions?


I have recently been messing with the Coroutine features in Unity and realised that I could not seem to stop a coroutine that relied on conditions with the StopCoroutine command.

My code is as follows:

horizontal = Input.GetAxisRaw("Horizontal");
        vertical = Input.GetAxisRaw("Vertical");

        Vector2 fwd = new Vector2(horizontal, vertical);
        fwd.Normalize();

        LayerMask layerMask = LayerMask.GetMask("Default"); //only looks for objects on the Default layer, means that players collider doesnt get hit by raycast

        RaycastHit2D hit = Physics2D.Raycast(raycastObject.transform.position, fwd, 50, layerMask); //raycast instantiates out in movement direction up to 50 units away
        Debug.DrawRay(raycastObject.transform.position, fwd * 50, Color.green); //editor raycast debug
        if (hit.collider != null && hit.collider.tag == "LightFood") //only interacts with 'Food' objects
        {
            IEnumerator liftCor = Lift(smallFruit * 2, hit.collider.gameObject);
            if (Input.GetKey(KeyCode.E))
            {
                if (antNum >= smallFruit) //this says that if there are less ants then required for the weight of the fruit (look above start function to see weights), then fruit isnt lifted
                {
                    StartCoroutine(liftCor); //lifts fruit according to its weight * 2 (since the weight is then divided by antnum, so its important cause math)
                    
                }
            }
            else
            {
                StopCoroutine(liftCor); //this seems not to be working :(
            }

        }
            
        

    private IEnumerator Lift(float weight, GameObject item)
    {
        weight = weight / antNum;
        Debug.Log(weight);
        yield return new WaitForSeconds(weight);
        item.SetActive(false);
    }

where antNum and smallFruit are arbitrary floats.

I have tried the Unity documentations suggestions of using strings to call the Coroutines or (as is shown in the code) first attributing the coroutines to an IEnumerator and calling them both from the same variable but I've had no luck, and I think this is likely due to the coroutine relying on a float and a gameobject.

If you have any suggestions on how to fix this problem I would be very grateful to hear them. Thank you!


Solution

  • Every time you call the Lift method, you create a new enumerator. So what you stopped is the new one, but what actually you want to stop is the previous one.

    There's another problem in your code. When you are pressing E you will start a new coroutine every frame, I don't think this is expected.

    Here's the solution, first you should define a coroutine object for refering the created coroutine.

    private Coroutine coroutineLift;
    

    Then you can use it to associate new coroutine and stop it.

    if (Input.GetKey(KeyCode.E))
    {
        if (antNum >= smallFruit && coroutineLift == null)
        {
            coroutineLift = StartCoroutine(Lift(smallFruit * 2, hit.collider.gameObject));                 
        }
    }
    else if (coroutineLift != null)
    {
        StopCoroutine(coroutineLift);
    }
    

    If you wish to continue creating new coroutine after the end of this coroutine, then you also need to clear coroutineLift at the end of Lift

    private IEnumerator Lift(float weight, GameObject item)
    {
        .....
        coroutineLift = null;
    }