Search code examples
c#unity-game-enginenew-operatorcoroutine

How to start and stop other coroutines from a OnTriggerStay coroutine


I am quite new to programming so any help is loved.

This in theory should work but for some reason when I run it in unity it just doesn't and I don't know why.

I want this damage system to work but I want the SFX and damage rate to be different however I am not sure how to do this and this is the best I was able to come up with.

ISSUES: Although it does apply damage it repeatedly stacks damage. And when I am not supposed to take damage it doesn't stop for some reason.

    IEnumerator OnTriggerStay2D(Collider2D collision)
    {
        if (collision.CompareTag("Damage"))
        {
            //The StopCoroutine here is supposed to stop it from stacking however I am getting 
            //mixed results
                 
            StopCoroutine(Damager());
            StopCoroutine(DamageSFX());

            StartCoroutine(Damager());
            StartCoroutine(DamageSFX());
        }
         
        //I feel like it should be an "else if" method but I'm not sure why or how

        else
        {
            StopCoroutine(Damager());
            StopCoroutine(DamageSFX());
        }

        yield return new WaitForEndOfFrame();
    }

    IEnumerator Damager()
    {
        while (true)
        {
            curruntHealth--;

            yield return new WaitForSeconds(Delay);
        }
    }

    IEnumerator DamageSFX()
    {
        while (true)
        {
            //This part works perfectly fine on its own but not in this context
            FindObjectOfType<AudioManager>().Play("Damage SFX");

            yield return new WaitForSeconds(SoundDelay);
        }
    }


Solution

  • you're close but a few things to look at here.

    First - you probably want a simple bool flag to check if you've started up the damaging coroutines, that would stop them being repeatedly created. And in the example you posted you'd want to hook up the Stop in OnTriggerExit2D(Collider2D other)

    Second - when you start a couroutine with the method I believe you have to get the reference to is to stop it. If you use a string instead it stops it easier. example of ref to couroutine and string calls

    Here's a sample that does what you need it to do. In place of the OnTriggerStay I'm just using a public bool I can toggle in the inspector.

    public bool iscolliding;
    
    float delay = 1f;
    float sounddelay = 3f;
    
    bool takingDamage = false;
    
    // ref to started coroutine for start/stop if you didn't want to use strings
    // private IEnumerator damageCoroutine;
    
    private void Update()
    {
        // we have a collision
        // this would be OnTriggerStay2D
        if (iscolliding)
        {
            // and we haven't stared our couroutines up
            if (!takingDamage)
            {
                StartCoroutine("Damager");
                StartCoroutine("DamageSFX");
                takingDamage = true; // flag on
            }
        }
        // else no collision
        // so check on OnTriggerExit2D
        else
        {
            // we're still taking damage, so stop the coroutines
            if (takingDamage)
            {
                StopCoroutine("Damager");
                StopCoroutine("DamageSFX");
                takingDamage = false; // flag off
            }
        }
    }
    
    IEnumerator Damager()
    {
        while (true)
        {
            Debug.Log("Taking damage");
            yield return new WaitForSeconds(delay);
        }
    }
    
    IEnumerator DamageSFX()
    {
        while (true)
        {
            //This part works perfectly fine on its own but not in this context
            Debug.Log("Play damage sound fx");
            yield return new WaitForSeconds(sounddelay);
        }
    }`