Again I would not reach for coroutines here.
The reason: you can go below the critical health, then go up, then go back down, and every single point in there is a chance to screw up how many coroutines are actually running.
Coroutines are great but they are the wrong solution for this problem.
Instead, make a heartbeat script and have a variable to count if it is time yet:
private float heartBeatYet;
In your Update() function, calculate the desired rate of heartbeat based on health:
float desiredInterval = 0; // no heartbeat
if (health < 15)
{
desiredInterval = 2.0f; // sorta hurting
}
if (health < 10)
{
desiredInterval = 1.5f; // hurting more
}
if (health < 5)
{
desiredInterval = 1.0f; // really hurting!
}
Now that you have that interval:
if (desiredInterval > 0)
{
// countdown until heartbeat needed
heartBeatYet -= Time.deltaTime;
// check if it is time for a heartbeat yet?
if (heartBeatYet <= 0)
{
// reset timer for next heartbeat
heartBeatYet += desiredInterval;
// lub-dup...
HeartBeatSound.Play();
}
}
DONE. Now you can have multiple “urgencies” of heartbeat, no coroutines to start, stop, keep track of, etc. It just runs forever. When nothing is happening the only cost is a couple of compare statements.