- Home /
Coroutine starts but doesn't run?
I am trying to implement a powerup that ends after a certain time and if another powerup is grabbed then time adds to the timer before de-activation.
I put my coroutine for the powerup time onto a PowerupManager script and made it public and static, and start it when the pickup is grabbed, like so:
if (PowerupManager.powerupActive == false) { PowerupManager.powerupActive = true; PowerupManager.timer = powerupTime; StartCoroutine(PowerupManager.PowerupTimer()); } else { PowerupManager.timer += powerupTime; }
Pretty straightforward. Then, the PowerupManager's coroutine should activate and do its thing:
public class PowerupManager : MonoBehaviour {
public static bool powerupActive = false;
public static float timer = 0f;
//Waits amount of time and then disables the powerup effects
public static IEnumerator PowerupTimer()
{
//At start of coroutine, set seconds elapsed to zero
float seconds = 0f;
//While seconds elapsed is less than the time to run, keep running this timer
//Check the condition every second in case the timeToKeepActive changes
while (seconds < timer)
{
Debug.Log((timer - seconds) + "seconds left to run");
yield return new WaitForSeconds(1f);
seconds++;
}
//[Code to deactivate powerup goes here]
powerupActive = false;
}
}
My pickup's powerupTime is set to 8f, so I should get the Debug.Log((timer - seconds) + "seconds left to run");
to print the amount of time left to run, counting down from 8 to zero. However it only prints "8 seconds left to run", and doesn't countdown any further. Not sure what's going on here so any help is appreciated!
Are you sure the object running the coroutine isn't disabled before the latter ends?
Answer by Bunny83 · Mar 05, 2019 at 10:13 AM
This line:
StartCoroutine(PowerupManager.PowerupTimer());
is equivalent to
this.StartCoroutine(PowerupManager.PowerupTimer());
That means you run the coroutine on the MonoBehaviour instance you're currently on. Since i guess this is a powerup object which you probably destroy or deactivate the coroutine will be terminated along with the object. Since you already have a PowerupManager you probably should start the coroutine on that instance.
Instead of using so many static variables, it's better to make your PowerupManager a singleton like this:
public class PowerupManager : MonoBehaviour
{
public static PowerupManager instance;
public bool powerupActive = false;
public float timer = 0f;
void Awake()
{
instance = this;
}
private IEnumerator PowerupTimer(float aTime)
{
powerupActive = true;
float seconds = 0f;
timer = aTime;
while (seconds < timer)
{
yield return new WaitForSeconds(1f);
seconds++;
}
powerupActive = false;
}
public void PowerupPickup(float aTime)
{
if (powerupActive == false)
{
StartCoroutine(PowerupTimer(aTime));
}
else
{
timer += aTime;
}
}
}
Inside your Powerup object you just would do:
PowerupManager.instance.PowerupPickup(powerupTime);
Of course your PowerupManager need to be attached to an object in the scene.
You guys nailed it, my powerup deletes itself after starting the timer, I wasn't aware that the coroutine runs on whichever script calls it. Thanks!