How can i make it that the Coroutine is only called once?

I want the script to constantly check the HP. Once it goes to or below zero, i want to start a Coroutine that plays ONCE and then ends. How can i achieve this?

In the following example i want to destroy the Ship and make it emmit smoke particles on death, all timed like in the code. However currently, it is spamming the explosion sound and the smoke particles because Update() plays it constantly.

void Awake()
{

    
    ship_hp = 10;
}


void Update()
{


    if (ship_hp == 0 || ship_hp <= 0)
    {
        //How can i start this Coroutiene only once and then end the rest?
        shipdeath = StartCoroutine(ShipDeath());
    }


    
}

IEnumerator ShipDeath()
{
  
        AS.PlayOneShot(explosion);
        
        yield return new WaitForSeconds(1);

        Instantiate(Particles, transform.position, Quaternion.identity);
        yield return new WaitForSeconds(5);
        gameObject.SetActive(false);
        
        
    

}

Steps to success:

  1. Make all HP computations happen in one spot, such as a TakeDamage(int damage) method.

  2. When you subtract HP, compare the before and after and if it goes from above zero to not above zero, do whatever you want.

void TakeDamage( int damage)
{
  int previous = hitpoints;
  hitpoints -= damage;
  if (previous > 0 && hitpoints <= 0)
  {
    // yer dead, do something once
  }
}

If you insist on constantly checking then you open yourself to a whole new class of possible bugs. You will need a bool, you will need to check the bool, you will need to set the bool, you will need to remember to reset that bool, etc, etc. I do not recommend this approach.

4 Likes

This is a great solution and after i implemented it, it works. However now everytime my Object takes damage, the Coroutine happens all over again.

Is there a way to let TakeDamage() play until it is over, and then stop the script?

The way to stop a coroutine is by putting a yield break; in there, but, coroutines only run once unless you use while true statements. Once the Ienumerator reads the yield break; it will stop the coroutine. But if you want the coroutine to play over and over, put your code inside of while(true) { code here…} inside of the coroutine. to stop the coroutine you can use StopCoroutine(ShipDeath()); somewhere else or you can put an if statement at the end of your code that leads to the yield break; Good luck.

1 Like